Overview
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. The Store API accepts slugs or prefixed IDs interchangeably for resource lookups. The Admin API resolves resources by prefixed ID only — slugs are not accepted.Slug Generation
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 |
Models with Slugs
| Resource | Slug Column | Translatable | Hierarchical |
|---|---|---|---|
| Product | slug | Yes | No |
| Category | permalink | Yes | Yes |
| Store | code | No | No |
Category Permalinks
Category slugs include the full parent path, making them hierarchical:Slug History
When a slug changes (e.g., a product is renamed), Spree records the old slug in its history table (friendly_id_slugs).
Note: the Store API product and category endpoints look up the current slug only (find_by! on the slug/permalink column) and do not automatically resolve retired slugs — a request using an old slug returns 404. To preserve SEO and avoid broken links, issue HTTP 301 redirects from old slugs to the current one in your storefront or application layer.
Internationalization
Products and categories support localized slugs — a different slug per locale. The locale is resolved from the request’sX-Spree-Locale header:
Reserved Words
Spree prevents certain words from being used as slugs to avoid route conflicts:new, edit, index, login, logout, admin, and others.
Related Documentation
- Products — Product catalog
- Translations — Multi-language content
- Querying — API resource lookup
- Store SDK Products —
client.products.get()slug/ID lookup

