Shopify slug generator: handles, handleize, and product URLs
Shopify calls slugs handles. Every product, collection, blog, page and article has one, and it lives in the URL. The platform auto-derives handles from titles, but the conversion has rules that bite when you do not plan ahead.
Handles are slugs in Shopify dialect
In Shopify, the URL segment after /products/ or /collections/ is the handle. A product titled Organic Cotton T-Shirt becomes /products/organic-cotton-t-shirt automatically. The handle is stored as a top-level field on the resource, separate from the title, and you can edit it from the admin under SEO settings on each product.
The conversion rule is the same idea you see across CMSs: lowercase, replace whitespace and most punctuation with dashes, drop characters that are not letters, digits or dashes. Shopify limits handles to 255 characters and forbids leading or trailing dashes. Trying to set /-shoes- gets quietly normalized to shoes on save.
What surprises new merchants is the handle does not change when the title changes. Once Shopify generates a handle on first save, future title edits leave the handle alone. That is intentional: the URL is stable for SEO. It also means a typo at creation time follows you forever unless you fix it manually.
Collisions append numeric suffixes
If you create two products called Sale Item, the first becomes /products/sale-item and the second becomes /products/sale-item-1. The third gets -2, the fourth -3, and so on. The pattern applies across the whole store within a resource type, and the counter does not reset when you delete a conflicting product. If you delete sale-item and create a new one, the new one becomes sale-item-1 because Shopify still has soft references.
You can avoid this by setting the handle explicitly at creation time. The admin UI exposes the URL handle field; the Admin REST API and GraphQL Admin API both accept handle on ProductInput. If you are bulk-importing via CSV, set the Handle column directly. Trusting auto-generation across an import of similarly-named products is how you end up with three SKUs on -1, -2, -3 URLs that nobody remembers.
Changing handles after publish creates a 301
Shopify automatically creates a URL redirect when you change a published product's handle. The old URL keeps working, returning a 301 to the new handle, and the redirect is visible under Online Store, Navigation, URL redirects in the admin. You can edit or delete it.
This makes handle changes safer than they are on most CMSs, but it is not a license to rename freely. Each redirect is a hop, and stacking redirects on top of redirects makes audits messy. If you spot a typo on day one, fix it and move on. If the product has been live for two years, the handle is the URL the world knows; weigh the SEO friction of any change against the cosmetic gain.
The redirect is created only for resources that were published. Products in draft status do not get the redirect treatment when you rename them, because there was nothing public to break.
Liquid handleize for theme work
Themes need to slugify strings constantly: tag URLs, custom collections, search queries. The handleize filter is the in-Liquid equivalent of the platform's slugifier:
{% assign slug = product.title | handleize %}
<a href="/products/{{ slug }}">{{ product.title }}</a>
handleize matches the conversion the platform uses on save, so a string passed through it produces the same handle Shopify would have generated. Use it when you build dynamic URLs from arbitrary text in templates, especially for tag pages and metafield-driven custom collections. Do not use url_encode for this: that escapes characters for query strings, not URL paths, and the output is wrong for a handle position.
Working example
liquid{%- comment -%}
Render a tag cloud where each tag links to a clean handle.
handleize matches Shopify's own slugification on save.
{%- endcomment -%}
<ul class="tag-cloud">
{% for tag in collection.all_tags %}
{% assign tag_slug = tag | handleize %}
<li>
<a href="{{ collection.url }}/{{ tag_slug }}">
{{ tag }}
</a>
</li>
{% endfor %}
</ul>
{%- comment -%} Programmatic example for product handle preview {%- endcomment -%}
{% assign preview = "Limited Edition: Summer 2026 Drop!" | handleize %}
<p>Handle preview: <code>{{ preview }}</code></p>
{%- comment -%} Outputs: limited-edition-summer-2026-drop {%- endcomment -%} Just need the result?
When you are mapping out a product launch and want the handles ready before you log into Shopify, the slug generator at aldeacode.com produces the same handleize output. Paste your draft titles, copy back the handles, and set each one explicitly in the URL handle field at creation. No surprise -1 suffixes, no later 301 cleanup.
Open URL Slug Generator →Frequently asked questions
Does Shopify update the handle when I rename a product?
No. The handle is set on first save and stays put unless you edit it explicitly under SEO settings. This protects URLs from accidental SEO loss when you tweak a title.
Can two products have the same handle?
Not within the same resource type. Shopify appends -1, -2 and so on to keep handles unique. The counter persists even after deletes, so freeing up a handle for reuse may require a manual cleanup.
Will old links break if I change a handle?
No for published products. Shopify auto-creates a 301 from the old handle to the new one, visible under URL redirects. Draft products do not get this treatment because nothing was public.