---
title: Slugs
description: How Spree generates SEO-friendly URL slugs for products, categories, and stores, and how to look up resources by slug or ID via the API.
---

## 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.


```typescript Store SDK
// 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')
```

```typescript Admin SDK
// Admin SDK accepts prefixed IDs only — not slugs
const product = await adminClient.products.get('prod_86Rf07xd4z')
```

```bash cURL
# By slug
curl 'https://api.mystore.com/api/v3/store/products/spree-tote' \
  -H 'X-Spree-API-Key: pk_xxx'

# By ID
curl 'https://api.mystore.com/api/v3/store/products/prod_86Rf07xd4z' \
  -H 'X-Spree-API-Key: pk_xxx'
```


## 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` |

If a slug already exists, Spree appends the SKU or a unique identifier to ensure uniqueness.

## 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:

```text
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.

## 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's [`X-Spree-Locale` header](../../api-reference/store-api/localization.md):


```typescript Store SDK
// English
const product = await client.products.get('red-shoes')

// French — locale goes in the third (request options) argument,
// which sends the X-Spree-Locale header
const product = await client.products.get('chaussures-rouges', undefined, {
  locale: 'fr',
})
```

```typescript Admin SDK
// Admin SDK accepts prefixed IDs only — not slugs
const product = await adminClient.products.get('prod_86Rf07xd4z')
```

```bash cURL
# English
curl 'https://api.mystore.com/api/v3/store/products/red-shoes' \
  -H 'X-Spree-API-Key: pk_xxx'

# French
curl 'https://api.mystore.com/api/v3/store/products/chaussures-rouges' \
  -H 'X-Spree-API-Key: pk_xxx' \
  -H 'X-Spree-Locale: fr'
```


Slugs are unique within the same locale but can be duplicated across different locales.

## 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](products.md) — Product catalog
- [Translations](translations.md) — Multi-language content
- [Querying](../../api-reference/store-api/querying.md) — API resource lookup
- [Store SDK Products](../sdk/store/products.md) — `client.products.get()` slug/ID lookup
