# Product URLs are SEO-friendly with slugs, not IDs

- **Pattern:** `ab-001131` (`ecommerce-catalog.search-discovery.seo-friendly-urls`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001131
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001131)

## Why it matters

URLs like `/products/clk123abc456` give search engines and humans zero keyword signal, cost rankings on long-tail product queries, and make every shared link look like spam. Competitors using slug-based URLs rank above you for the same inventory. Swapping product platforms or re-seeding the database also breaks every external link because IDs shift, whereas stable slugs survive migrations and preserve the findability equity you already earned.

## Severity rationale

Low because the catalog still functions, but ID-based URLs permanently suppress organic traffic and link equity.

## Remediation

Add a unique `slug` column to the product model in `prisma/schema.prisma`, backfill it from product names, then move the route to `src/app/products/[slug]/page.tsx` and look up by slug:

```prisma
model Product {
  id   String @id @default(cuid())
  slug String @unique
}
```

```tsx
export default async function ProductPage({ params }) {
  const product = await prisma.product.findUnique({ where: { slug: params.slug } })
}
```

## Detection

- **ID:** `seo-friendly-urls`
- **Severity:** `low`
- **What to look for:** Count all product page routes in the codebase. Enumerate the URL pattern used: `src/app/products/[id]/page.tsx` (ID-based) vs `src/app/products/[slug]/page.tsx` (slug-based). Check the product schema for a `slug` field with a unique constraint. If using Next.js, check `generateStaticParams` or dynamic route parameter names.
- **Pass criteria:** Product page routes use descriptive slugs (e.g., `/products/[slug]/page.tsx`) and the product schema has a `slug` field with `@unique` constraint. At least 90% of products in seed data have meaningful slugs (not UUIDs or numeric IDs). Report: "URL pattern: [pattern], X of Y products have meaningful slugs."
- **Fail criteria:** Product URLs use only numeric IDs or UUIDs (e.g., `/products/[id]/page.tsx` with `id` being a UUID), or the product schema has no slug field.
- **Skip (N/A) when:** Products are accessed via API only, not through human-readable URLs — confirmed by absence of product page routes in `src/app/`.
- **Cross-reference:** For URL structure and crawlability, the SEO Fundamentals audit covers URL patterns, redirects, and canonical tags.
- **Cross-reference:** For slug generation and uniqueness, the Database Design & Operations audit covers unique constraint patterns.
- **Cross-reference:** For slug-based routing performance, the Performance Core audit covers static generation and ISR patterns.
- **Detail on fail:** `"Product page at src/app/products/[id]/page.tsx uses UUID-based URLs: /products/clk123abc456"`
- **Remediation:** Add a slug field to `prisma/schema.prisma` and use it in routes:

  ```prisma
  model Product {
    id String @id @default(cuid())
    slug String @unique
  }
  ```

  In `src/app/products/[slug]/page.tsx`:

  ```tsx
  export default async function ProductPage({ params }) {
    const product = await prisma.product.findUnique({
      where: { slug: params.slug },
    })
  }
  ```

Taxons: findability

HTML version: https://auditbuffet.com/patterns/ab-001131
