Directories

SEO architecture for large Next.js directories

Give each published listing its own metadata, a stable slug URL, and a sitemap without indexing pending submissions.

2 min read

A directory ranks when each record is a real URL with a title and a description taken from that record. The Directory Starter already has the route and the metadata function. This page is how to extend that pattern once you have more than a handful of listings. The data model is in building a directory with Next.js.

One URL per listing

Use /listings/[slug], and make slug unique in Prisma. Do not key the public URL on the cuid. A slug survives a database restore and is what you put in internal links. Unpublished rows (status is not "published") must notFound() so they do not return 200 with thin content.

Metadata from the row

export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
  const listing = await prisma.listing.findUnique({
    where: { slug: (await params).slug }
  });
  return {
    title: listing?.title || "Listing",
    description: listing?.summary
  };
}

description should be the listing summary you are willing to show in a search result, not a copy of the title. Keep summaries written for humans. The kit stores summary as a required string, so you always have something to return.

Set the canonical URL to the slug path. If the same listing is also reachable with a query string (?ref=), the canonical should omit it. Next.js accepts alternates.canonical in the metadata object. Add it when you introduce tracking parameters. The starter’s metadata function does not set canonical yet.

Sitemap

A sitemap for this app is a server route or app/sitemap.ts that queries status: "published" and emits /listings/{slug}. Do not list pending rows. Regenerate from the database on request; do not commit a static file of slugs if editors add listings in production.

Category pages (/categories/[slug]) should exist when a category has enough unique text to be a page. A category that only repeats listing titles is optional. The starter’s public listing page is the one with its own generateMetadata.

What not to do

Do not render thousands of listings in one client component for the sake of a single page. Paginate the index. Do not noindex the listing page and expect the homepage to carry the catalog. Each published listing is the page you want fetched.

The Job Board Starter has the same shape for jobs and companies. The same metadata and sitemap rules apply, with the extra constraint that unpaid submissions stay pending.

Want to skip the setup? The Directory Starter already serves a metadata title and description for each published listing slug.

Product updates for developers shipping with Designyff kits.

Purchased source may be used in personal, commercial, and client projects. Do not redistribute or resell the original source. Terms of Service

Designyff © 2026 | Starter kits for developers | Powered by  Tacko