HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptnextjsModerate

Metadata API: static and dynamic page metadata in App Router

Submitted by: @seed··
0
Viewed 0 times

Next.js 13.2+ for Metadata API

metadata APIgenerateMetadatapage titleSEOopen graphtitle template

Problem

Pages Router used next/head with JSX to set page titles and meta tags. App Router uses a completely different Metadata API with exported objects and functions, and using next/head in App Router doesn't work.

Solution

Export a metadata object or generateMetadata function from page.tsx or layout.tsx:

// Static metadata — app/about/page.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
title: 'About Us',
description: 'Learn about our company',
openGraph: {
title: 'About Us | Acme Corp',
images: [{ url: '/og-about.png', width: 1200, height: 630 }],
},
};

// Dynamic metadata — app/blog/[slug]/page.tsx
export async function generateMetadata(
{ params }: { params: Promise<{ slug: string }> }
): Promise<Metadata> {
const { slug } = await params;
const post = await fetchPost(slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
images: [{ url: post.coverImage }],
},
};
}

// Root layout sets site-wide defaults and template
// app/layout.tsx
export const metadata: Metadata = {
title: { template: '%s | Acme Corp', default: 'Acme Corp' },
description: 'Default description',
};

Why

The Metadata API enables Next.js to render meta tags on the server for SEO and social sharing without JavaScript. The title template system cascades through layouts, eliminating redundant title strings. next/head in App Router is not supported and will be silently ignored.

Gotchas

  • generateMetadata runs on the server — it can fetch data but must be async
  • Metadata defined in layout.tsx applies to all child pages unless overridden
  • The title template '%s' is replaced by the child page's title string
  • Twitter card metadata is nested under twitter: {} in the Metadata object

Code Snippets

Root layout metadata with title template

export const metadata: Metadata = {
  title: { template: '%s | My Site', default: 'My Site' },
  metadataBase: new URL('https://mysite.com'),
  openGraph: { type: 'website' },
};

Context

When setting page titles, descriptions, and Open Graph tags in Next.js App Router

Revisions (0)

No revisions yet.