Skip to content
Watch the complete Next.js 15 course on YouTube

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
    • layout.tsx
    • page.tsx /
app/layout.tsx
export const metadata = {
title: "unofficialDocs",
description: "The second best Next.js documentation",
};
app/about/page.tsx
export const metadata = {
title: "About unofficialDocs",
};

When metadata exists at multiple levels, they merge with more specific routes taking precedence:

  1. Root layout metadata applies globally
  2. Child route metadata overrides matching properties
  3. 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.

app/products/[id]/page.tsx
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:

  1. Create a client component for interactive features:
src/components/counter.tsx
"use client";
import { useState } from "react";
export const Counter = () => {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
};
  1. Use it in your server component with metadata:
app/page.tsx
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