- Next.js
- Dynamic Metadata & SEO
- Static vs Dynamic Metadata Generation
Static vs Dynamic Metadata Generation
Next.js provides two ways to define SEO tags: static metadata via the export const metadata object, and dynamic metadata via the generateMetadata async function. Metadata merges hierarchically from root layouts down to nested pages, with leaf pages overriding parent properties while inheriting un-overridden defaults.
Learning Objectives
Define static metadata with title templates and base descriptions.
Implement async generateMetadata() to fetch product or article metadata dynamically.
Explain metadata inheritance and cascading merge rules across layouts and pages.
Ensure data fetch requests in generateMetadata are deduplicated with page queries.
Prerequisites & Background Knowledge
Why Interviewers Care
Every production application requires dynamic SEO metadata for search engine indexing and social sharing cards.
The Challenge
Contrast static metadata with dynamic generateMetadata. Implement a product detail page that dynamically generates SEO titles, descriptions, and OpenGraph tags, and explain how Next.js handles request deduplication.
Code Architecture & Implementation
1// app/products/[slug]/page.tsx2import { Metadata } from 'next';3import { notFound } from 'next/navigation';45interface ProductPageProps {6 // In Next.js 15+, params is a Promise!7 params: Promise<{ slug: string }>;8}910// Automatically called by Next.js to populate <head> tags11export async function generateMetadata({ params }: ProductPageProps): Promise<Metadata> {12 const { slug } = await params;1314 // This fetch is automatically deduplicated with the fetch inside the page component!15 const product = await fetch(`https://api.store.com/products/${slug}`).then(res => res.json());1617 if (!product) {18 return { title: 'Product Not Found' };19 }2021 return {22 title: product.name,23 description: product.description.slice(0, 160),24 openGraph: {25 title: product.name,26 description: product.description,27 images: [{ url: product.featuredImage, width: 1200, height: 630 }],28 },29 alternates: {30 canonical: `/products/${slug}`,31 },32 };33}3435export default async function ProductDetailPage({ params }: ProductPageProps) {36 const { slug } = await params;37 const product = await fetch(`https://api.store.com/products/${slug}`).then(res => res.json());3839 if (!product) notFound();4041 return <div><h1>{product.name}</h1></div>;42}
Architectural Explanation
Search crawlers expect <title>, <meta name="description">, and OpenGraph tags in the initial HTML document. generateMetadata allows you to fetch CMS data and return a strongly typed Metadata object. Thanks to Next.js request memoization, if both generateMetadata and page.tsx call fetch("https://api.store.com/products/123"), Next.js only executes one network call, caching the result in-memory for the render pass.
Common Mistakes & Anti-Patterns
Exporting both `metadata` AND `generateMetadata` from the same file, which causes a build error.
Forgetting that `generateMetadata` can only be exported from Server Components (pages or layouts), not Client Components.
Not using title templates (`%s`), leading to inconsistent branding across pages.
Interview Follow-Up Traps
The interviewer asks: "Does calling cookies() inside generateMetadata make the whole page dynamic?" Yes! Dynamic functions inside generateMetadata trigger dynamic rendering for the route.
Frequently Asked Questions
What is metadataBase and why should you configure it?
`metadataBase` defines the base URL (e.g. `https://example.com`) for resolving relative OpenGraph image URLs.
How do you handle 404 pages in generateMetadata?
You can call `notFound()` or return a fallback `{ title: "Not Found" }`.
