Skip to main content

Product URLs are SEO-friendly with slugs, not IDs

ab-001131 · ecommerce-catalog.search-discovery.seo-friendly-urls
Severity: lowactive

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:

model Product {
  id   String @id @default(cuid())
  slug String @unique
}
export default async function ProductPage({ params }) {
  const product = await prisma.product.findUnique({ where: { slug: params.slug } })
}

Detection

  • ID: ecommerce-catalog.search-discovery.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:

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

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

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

Taxons

History