Loading lessons...
Dynamic Metadata & SEO Optimization
Dynamic Metadata & SEO Optimization
Next.js provides a robust Metadata API to manage document head tags (<title>, <meta>, OpenGraph, Twitter cards) for search engine optimization (SEO) and social media sharing.
1. Static Metadata Export
Export a static metadata object from any layout.tsx or page.tsx:
// app/about/page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'About Us | TechCorp',
description: 'Learn about TechCorp and our full-stack engineering team.',
openGraph: {
title: 'About Us | TechCorp',
description: 'Learn about TechCorp and our full-stack engineering team.',
url: 'https://techcorp.com/about',
siteName: 'TechCorp',
images: [{ url: 'https://techcorp.com/og-about.png', width: 1200, height: 630 }],
locale: 'en_US',
type: 'website',
},
};
export default function AboutPage() {
return <main>About Content</main>;
}
2. Dynamic Metadata Generation (generateMetadata)
For dynamic pages (such as app/blog/[slug]/page.tsx), generate metadata programmatically using generateMetadata():
// app/blog/[slug]/page.tsx
import { Metadata } from 'next';
import db from '@/lib/db';
type Props = {
params: Promise<{ slug: string }>;
};
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = await params;
const post = await db.post.findUnique({ where: { slug } });
if (!post) {
return { title: 'Post Not Found' };
}
return {
title: `${post.title} | Tech Blog`,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [post.coverImage],
},
};
}
export default async function BlogPostPage({ params }: Props) {
const { slug } = await params;
return <article>Article body for {slug}</article>;
}
Dynamic Sitemaps and Robots (sitemap.ts & robots.ts)
Generate sitemaps dynamically by creating app/sitemap.ts:
// app/sitemap.ts
import { MetadataRoute } from 'next';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
return [
{
url: 'https://example.com',
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 1,
},
{
url: 'https://example.com/blog',
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.8,
},
];
}
Metadata Rules
- Metadata is evaluated from parent to child: Root Layout -> Page Metadata.
- Metadata fields are merged; deeper child routes overwrite matching parent title/description fields.
TL;DR
- Export static metadata using
export const metadata: Metadata = { ... }. - Export dynamic metadata for variable routes using
export async function generateMetadata({ params }). - Manage OpenGraph and Twitter cards directly inside the metadata object.
- Automatically generate sitemaps using
app/sitemap.ts.