Routing metadata
This page explains how to handle metadata for routes in Next.js using both static and dynamic approaches.
Metadata API
Next.js provides built-in SEO support through its Metadata API, which allows you to define metadata for individual routes. The metadata flows from root level downward, with page-level metadata taking precedence over layout metadata for matching properties.
The App router supports two approaches for handling metadata in layout.tsx
or page.tsx
files: a static metadata object or a dynamic generateMetadata
function.
Static metadata
To define static metadata, export a metadata object from your layout.tsx
or page.tsx
file:
Directoryapp/
Directoryabout/
- page.tsx
/about
- page.tsx
- layout.tsx
- page.tsx
/
export const metadata = { title: "unofficialDocs", description: "The second best Next.js documentation",};
export const metadata = { title: "About unofficialDocs",};
When metadata exists at multiple levels, they merge with more specific routes taking precedence:
- Root layout metadata applies globally
- Child route metadata overrides matching properties
- Page metadata has highest priority
In the example above, the home page renders with the title “unofficialDocs” and the description “The second best Next.js documentation”. The about page renders with the title “About unofficialDocs” and the same description.
Dynamic metadata
For routes that require dynamic information—such as route parameters, external data, or parent segment metadata—export a generateMetadata
function from your layout.tsx
or page.tsx
file.
import { Metadata } from "next";
type Props = { params: Promise<{ id: string }>;};
export const generateMetadata = async ({ params,}: Props): Promise<Metadata> => { const { id } = await params; // Fetch product data from an API or database const product = await fetch(`https://api.example.com/products/${id}`); const productData = await product.json(); return { title: productData.name, description: productData.description, };};
Client components and metadata
Metadata API doesn’t work in client components (marked with ‘use client’). Instead:
- Create a client component for interactive features:
"use client";import { useState } from "react";
export const Counter = () => { const [count, setCount] = useState(0); return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;};
- Use it in your server component with metadata:
import { Counter } from "../components/counter";
export const metadata = { title: "Counter Page",};
export default function Page() { return <Counter />;}
This approach allows you to maintain metadata functionality while using client-side features.
Good to know
- Cannot use both static metadata and generateMetadata in same route
- Metadata merges automatically through the route hierarchy
- Client components must extract metadata to parent server components