Next.js SEO + Metadata Rules
Metadata API, sitemap, robots, OG images, and structured data done right.
# CLAUDE.md — Next.js SEO + Metadata
## Metadata API
- Every page exports `metadata` (static) or `generateMetadata` (dynamic). No exceptions.
- Always set: `title`, `description`, `alternates.canonical`, `openGraph`, `twitter`, `robots`.
- Title pattern: `${PageName} | ${SiteName}`. Set the suffix once via `metadata.title.template` in the root layout.
- Description: 140–160 characters. Avoid keyword stuffing — write a real sentence.
## Canonical URLs
- Set `alternates.canonical` to the absolute URL on every indexable page.
- For paginated routes, the canonical should point to the *current* page, not page 1. Don't auto-rewrite to page 1.
- Trailing slashes: pick one and stick with it via `next.config.ts` `trailingSlash`.
## Sitemap & robots
- `app/sitemap.ts` exports a function returning `MetadataRoute.Sitemap`. Generate from your data — never hand-maintain.
- `app/robots.ts` exports a function returning `MetadataRoute.Robots`. Reference the sitemap.
- Exclude staging, admin, and search-result pages with `disallow`. Don't rely on auth alone.
## OG images
- One `opengraph-image.tsx` per route segment. Use `next/og`'s `ImageResponse`.
- Size: 1200×630. `runtime: 'nodejs'` if you read from the filesystem; otherwise `'edge'` is fine.
- Pre-render dynamic OG images via `generateStaticParams` so they're cached at the CDN.
## Structured data (JSON-LD)
- Add a `<script type="application/ld+json">` per page where it applies — `Article`, `Product`, `BreadcrumbList`, `FAQPage`, `SoftwareApplication`.
- Use `dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}` — don't render JSON-LD as a child string.
- Validate with Google's Rich Results Test before claiming the page is "done".
## Performance signals
- Ship `priority` only on the LCP image (one per page).
- `next/font` for fonts — never `<link>` to Google Fonts.
- Avoid client components on static content. Server Components ship zero JS.
## Internal linking
- Use `<Link>` for same-origin navigation. Never `<a href>`.
- Crawlers follow `<Link>`. They do *not* follow JavaScript-only navigation.
## Don't
- Don't dynamically generate canonical URLs on the client.
- Don't `noindex` pages by accident — review your `robots` field per page.
- Don't ship a single shared OG image when you can ship per-page images.
- Don't write meta tags by hand with `<meta>` in your JSX. Use the Metadata API.
Other Next.js templates
Next.js App Router + TypeScript Rules
Server Components, Server Actions, and TypeScript discipline for the Next.js App Router.
Next.js + Server Actions + Shadcn UI
Forms with Server Actions, Zod validation, and Shadcn UI primitives.
Next.js + Supabase Auth
Auth flows with Supabase SSR, cookies, and Row Level Security policies.
Next.js + Tailwind + Prisma Stack
Full-stack Next.js with Prisma ORM, Tailwind CSS, and Postgres.