Correct metadata decides how pages appear in search results and link previews.
Next.js manages <head> through the Metadata API, only in Server Components (layouts and pages):
- Static:
export const metadata: Metadata = { title: 'About', description: '...' }. - Dynamic:
export async function generateMetadata({ params })returns metadata based on data, e.g. a blog post's title. Fetches inside it are memoised with the page's identical requests. - Metadata merges from the root layout down; a page overrides fields of its parents.
- Title templates: in a layout,
title: { template: '%s | Acme', default: 'Acme' }turns a page'stitle: 'Pricing'into "Pricing | Acme". openGraph,twitter,alternates.canonical,robotsandiconscover social previews and SEO. SetmetadataBasein the root layout so relative URLs resolve to absolute ones.
File conventions generate assets and routes:
opengraph-image.tsx(or.png) creates the social preview image; dynamic ones useImageResponsefromnext/ogto render JSX to a PNG.icon.png,apple-icon.png,favicon.icoinapp/become icons.sitemap.tsandrobots.tsexport functions returning typed objects (MetadataRoute.Sitemap,MetadataRoute.Robots) that become/sitemap.xmland/robots.txt.
Use generateViewport or export const viewport for viewport and theme colour settings.
Example
// app/layout.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://acme.com'),
title: { template: '%s | Acme', default: 'Acme' },
description: 'Tools for builders',
}
// app/blog/[slug]/page.tsx
import { getPost } from '@/lib/posts'
export async function generateMetadata({ params }: PageProps<'/blog/[slug]'>): Promise<Metadata> {
const post = await getPost((await params).slug)
return {
title: post.title, // -> "My Post | Acme"
description: post.excerpt,
openGraph: { type: 'article', images: [post.coverUrl] },
}
}
// app/sitemap.ts
import type { MetadataRoute } from 'next'
export default function sitemap(): MetadataRoute.Sitemap {
return [{ url: 'https://acme.com', lastModified: new Date() }]
}Remember
- Export
metadataorgenerateMetadatafrom layouts and pages (server only) - Metadata merges top-down; title templates add a site suffix
opengraph-image,icon,sitemap.ts,robots.tsare file conventions
Watch out for
- Adding
<title>tags manually in components or exporting metadata from a Client Component; use the Metadata API in server files.