Real World Example

SEO-friendly Product URLs

Flipkart and Amazon put the product name in the URL (/redmi-note-14-5g/p/itm123) because readable URLs rank better and look trustworthy when shared. ShopEase uses /products/[slug] where slug = name + id, e.g. /products/redmi-note-14-5g-42.

Example

Make a slug from a product name and read the id back from it:

function slugify(text: string): string {
  return text
    .toLowerCase()
    .normalize('NFKD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
}

function productSlug(name: string, id: number): string {
  return slugify(name) + '-' + id;
}

function idFromSlug(slug: string): number | null {
  const m = /-(\d+)$/.exec(slug);
  return m ? Number(m[1]) : null;
}

const slug = productSlug('Redmi Note 14 5G (8GB / 128GB)', 42);
console.log(slug);
console.log(idFromSlug(slug));
console.log(productSlug("Levi's 511 Slim Jeans – Blue", 7));
console.log(idFromSlug('no-id-here'));

Output

redmi-note-14-5g-8gb-128gb-42
42
levi-s-511-slim-jeans-blue-7
null

The Page

app/products/[slug]/page.tsx reads the id from the slug and redirects old or wrong slugs to the correct one (so Google sees one URL per product):

import { notFound, permanentRedirect } from 'next/navigation';
import { getProduct } from '@/lib/products';
import { idFromSlug, productSlug } from '@/lib/slug';

export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const id = idFromSlug(slug);
  if (id === null) notFound();

  const product = await getProduct(id);
  if (!product) notFound();

  const correct = productSlug(product.name, product.id);
  if (slug !== correct) permanentRedirect('/products/' + correct);

  return <h1>{product.name}</h1>;
}