Next.js cookbook · Beginner

Add SEO metadata, Open Graph and sitemaps

Give every page correct titles, descriptions, social previews and a sitemap for search engines.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Export static metadata in layouts and generateMetadata for dynamic pages (it can reuse cached data fetches). Add app/sitemap.ts and app/robots.ts, and opengraph-image.tsx for generated social images.

Solution

// app/layout.tsx
import type { Metadata } from "next";
export const metadata: Metadata = {
  metadataBase: new URL("https://shop.example.com"),
  title: { default: "Acme Shop", template: "%s · Acme Shop" },
  description: "Quality gear for developers.",
};

// app/products/[slug]/page.tsx
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }): Promise<Metadata> {
  const product = await getProductBySlug((await params).slug);   // deduplicated with the page's fetch
  if (!product) return { title: "Not found" };
  return {
    title: product.name,
    description: product.summary,
    alternates: { canonical: `/products/${product.slug}` },
    openGraph: { title: product.name, images: [{ url: product.imageUrl, width: 1200, height: 630 }] },
  };
}

// app/sitemap.ts
import type { MetadataRoute } from "next";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const products = await listProductSlugs();
  return [
    { url: "https://shop.example.com", changeFrequency: "daily", priority: 1 },
    ...products.map((p) => ({ url: `https://shop.example.com/products/${p.slug}`, lastModified: p.updatedAt })),
  ];
}

Pitfalls

  • Duplicate titles across pages.
  • Missing canonical URLs for filtered/paginated variants.
  • Fetching the same data twice without caching (cache() / fetch dedupe).

Variations

  • JSON-LD structured data via a <script type="application/ld+json"> in the page.

Further reading: Next.js: Metadata and OG images

Reference: https://nextjs.org/docs/app/getting-started/metadata-and-og-images

More Next.js recipes

Was this page helpful?