docs/developer/core-concepts/slugs.mdx
Spree generates SEO-friendly URL slugs for resources like products, categories, and stores. Instead of accessing resources by ID, you can use clean, readable URLs based on resource names.
Both the Store API and Admin API accept slugs or IDs interchangeably for resource lookups.
<CodeGroup>// Both work — slug or ID
const product = await client.products.get('spree-tote')
const product = await client.products.get('prod_86Rf07xd4z')
// Categories use permalink slugs
const category = await client.categories.get('clothing/shirts')
# By slug
curl 'https://api.mystore.com/api/v3/store/products/spree-tote' \
-H 'Authorization: Bearer pk_xxx'
# By ID
curl 'https://api.mystore.com/api/v3/store/products/prod_86Rf07xd4z' \
-H 'Authorization: Bearer pk_xxx'
Slugs are automatically generated from resource names:
| Input | Generated Slug |
|---|---|
Spree T-Shirt | spree-t-shirt |
Café & Restaurant | cafe-and-restaurant |
Summer Collection 2025 | summer-collection-2025 |
If a slug already exists, Spree appends the SKU or a unique identifier to ensure uniqueness.
| Resource | Slug Column | Translatable | Hierarchical |
|---|---|---|---|
| Product | slug | Yes | No |
| Category | permalink | Yes | Yes |
| Store | code | No | No |
| Post | slug | Yes | No |
Category slugs include the full parent path, making them hierarchical:
clothing → "clothing"
clothing/shirts → "clothing/shirts"
clothing/shirts/t-shirts → "clothing/shirts/t-shirts"
When a parent category is renamed, all child permalinks update automatically.
When a slug changes (e.g., a product is renamed), Spree preserves the old slug. Requests using old slugs still find the resource, enabling:
Products, categories, and posts support localized slugs — a different slug per locale:
<CodeGroup>// English
const product = await client.products.get('red-shoes')
// French (with locale header)
const product = await client.products.get('chaussures-rouges', {
locale: 'fr',
})
# English
curl 'https://api.mystore.com/api/v3/store/products/red-shoes' \
-H 'Authorization: Bearer pk_xxx'
# French
curl 'https://api.mystore.com/api/v3/store/products/chaussures-rouges' \
-H 'Authorization: Bearer pk_xxx' \
-H 'X-Spree-Locale: fr'
Slugs are unique within the same locale but can be duplicated across different locales.
Spree prevents certain words from being used as slugs to avoid route conflicts: new, edit, index, login, logout, admin, and others.