Metadata, SEO & the Head
⏱ 12 min read read
Static Metadata --- Export an Object:
// app/about/page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'About Us --- My App',
description: 'Learn about our mission and team.',
keywords: ['about', 'team', 'company'],
openGraph: {
title: 'About Us',
description: 'Learn about our mission.',
url: 'https://myapp.com/about',
images: [{ url: 'https://myapp.com/og.png', width: 1200, height:
630 }],
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: 'About Us',
},
};
Dynamic Metadata --- generateMetadata Function:
// app/blog/[slug]/page.tsx
export async function generateMetadata(
{ params }: { params: { slug: string } }
): Promise<Metadata> {
const post = await getPostBySlug(params.slug);
if (!post) return { title: 'Post Not Found' };
return {
title: `${post.title} --- My Blog`,
description: post.excerpt,
openGraph: { title: post.title, images: [{ url: post.ogImage }] },
};
}
Title Template --- Avoid Repeating Site Name:
// app/layout.tsx
export const metadata: Metadata = {
title: {
default: 'My App',
template: '%s --- My App', // '%s' is replaced by page title
},
description: 'The best app ever.',
};
// app/about/page.tsx --- just set 'About Us'
export const metadata: Metadata = { title: 'About Us' };
// → renders as 'About Us --- My App'
Next.js 13+ handles all <head> tags via the Metadata API --- no
next/head needed.
Metadata is automatically deduped and merged from layouts → pages.
Use the Next.js favicon.ico file convention: place in
app/favicon.ico.
Robots, sitemap: app/robots.ts and app/sitemap.ts for dynamic
generation.
// app/about/page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'About Us --- My App',
description: 'Learn about our mission and team.',
keywords: ['about', 'team', 'company'],
openGraph: {
title: 'About Us',
description: 'Learn about our mission.',
url: 'https://myapp.com/about',
images: [{ url: 'https://myapp.com/og.png', width: 1200, height:
630 }],
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: 'About Us',
},
};
Dynamic Metadata --- generateMetadata Function:
// app/blog/[slug]/page.tsx
export async function generateMetadata(
{ params }: { params: { slug: string } }
): Promise<Metadata> {
const post = await getPostBySlug(params.slug);
if (!post) return { title: 'Post Not Found' };
return {
title: `${post.title} --- My Blog`,
description: post.excerpt,
openGraph: { title: post.title, images: [{ url: post.ogImage }] },
};
}
Title Template --- Avoid Repeating Site Name:
// app/layout.tsx
export const metadata: Metadata = {
title: {
default: 'My App',
template: '%s --- My App', // '%s' is replaced by page title
},
description: 'The best app ever.',
};
// app/about/page.tsx --- just set 'About Us'
export const metadata: Metadata = { title: 'About Us' };
// → renders as 'About Us --- My App'
Next.js 13+ handles all <head> tags via the Metadata API --- no
next/head needed.
Metadata is automatically deduped and merged from layouts → pages.
Use the Next.js favicon.ico file convention: place in
app/favicon.ico.
Robots, sitemap: app/robots.ts and app/sitemap.ts for dynamic
generation.
Log in to track your progress and earn badges as you complete lessons.
Log In to Track Progress