Write unique titles and descriptions in Next.js
Next.js resolves metadata from the page up to the layout, so a title set once in the root layout repeats on every route. Export a title and description per page, or generate them from record data in generateMetadata. Use title.template for the site suffix, keep descriptions unique, and verify the rendered HTML rather than the component source.
Why this matters
Per-route metadata exports beat one global title tag.
Before you start
- Next.js project with the App Router or a Pages Router equivalent
- A site name and suffix chosen for the title template
How to apply it
Set the title template and defaults
In app/layout.tsx export metadata with title.template set to '%s — <site name>' and title.default for the homepage. Do not export route-specific titles from the layout.
Check: grep -n 'template' app/layout.tsx shows the suffix, and no route-specific title sits in the layout.
Export per-page metadata
In each page.tsx export a metadata object with a unique title and a 120-160 character description that matches the visible content of that page.
Check: curl -s your production domain/<path> | grep -o '<title>[^<]*' prints a page-specific title.
Generate metadata for dynamic routes
In app/blog/[slug]/page.tsx await params, load the record, and return title and description from generateMetadata so each record gets its own values.
Check: curl -s your production domain/blog/<slug> | grep -o '<title>[^<]*' differs between two records.
Check for duplicates after deploy
Crawl the sitemap and compare extracted titles and descriptions. Rewrite any page that still shows the layout default or duplicates another route.
Check: A crawl of 20 sitemap URLs returns 20 distinct titles and at least 18 distinct descriptions.
Source: seo-mcp playbook · curated entry · report an error
Official references
Framework notes
nextjs-app
Set `metadata.title.template` and `title.default` in `app/layout.tsx`; export `title` and `description` from each `page.tsx`, and build dynamic values in `generateMetadata`.
nextjs-pages
Set titles with `next/head` or `NextSeo` per page; keep `_app.tsx` free of route-specific titles so pages do not inherit one value.