Metadata API & SEO
Control titles, descriptions, Open Graph tags, and more per route using the built-in Metadata API.
Static Metadata
Any page.tsx or layout.tsx can export a metadata object to define its <title>, description, and other head tags — no manual <head> manipulation required.
// app/about/page.tsxexport const metadata = { title: 'About Us | PrograMinds', description: 'Learn about our mission to make programming education accessible.',};
export default function AboutPage() { return <h1>About Us</h1>;}Dynamic Metadata with generateMetadata
For metadata that depends on fetched data — like a blog post's own title — export an async generateMetadata function instead of a static object.
// app/blog/[slug]/page.tsxexport async function generateMetadata({ params }) { const post = await getPostBySlug(params.slug); return { title: `${post.title} | PrograMinds Blog`, description: post.excerpt, };}If generateMetadata and the page component both need the same data, wrap the fetch in React's cache() function — Request Memoization then ensures the underlying fetch only actually runs once per request.
Metadata Inheritance
Metadata defined in a layout applies to every page beneath it, and a page's own metadata merges with (and can override) its parent layout's values — you don't need to repeat shared fields like a site-wide title template on every page.
// app/layout.tsxexport const metadata = { title: { template: '%s | PrograMinds', default: 'PrograMinds' },};// A page setting title: 'About Us' renders as "About Us | PrograMinds"Open Graph & Social Sharing
The same metadata object controls how a page looks when shared on social platforms, via the openGraph field.
export const metadata = { title: 'PrograMinds — Learn to Code', openGraph: { title: 'PrograMinds — Learn to Code', description: 'Free, comprehensive programming courses.', images: ['/og-image.png'], },};Sitemaps & robots.txt
Next.js also lets you generate sitemap.xml and robots.txt dynamically, as special files, so search engines get accurate crawling instructions straight from your app's own data.
// app/sitemap.tsexport default async function sitemap() { const posts = await getAllPosts(); return posts.map(post => ({ url: `https://example.com/blog/${post.slug}`, lastModified: post.updatedAt, }));}Common Beginner Mistakes
This bypasses the Metadata API entirely and can conflict with it — use the exported metadata object or generateMetadata instead.
metadata and generateMetadata can only be exported from Server Components, not from files marked "use client".
FAQs
Yes, generateMetadata can read request-specific data just like a page can, though doing so makes that route dynamically rendered.
For most needs, yes — the built-in Metadata API covers titles, Open Graph, Twitter cards, and more without an extra dependency.
Summary
The Metadata API gives every route precise, mergeable control over its SEO tags, with dynamic support for content-driven pages. Next, you'll look at the different ways to style a Next.js application.