Part 2 of 22

Metadata API: titles, descriptions and the template pattern

The App Router replaced next/head with the typed Metadata API. Two ways to use it — static export for fixed pages, generateMetadata for dynamic ones:

// app/layout.tsx — site-wide defaults with a title template
import type { Metadata } from "next";

export const metadata: Metadata = {
  metadataBase: new URL("https://example.com"),
  title: {
    template: "%s | Acme",
    default: "Acme — Web Development Studio",
  },
  description: "Default description used when a page doesn't set its own.",
};
// app/blog/[slug]/page.tsx — dynamic metadata per post
export async function generateMetadata({ params }): Promise<Metadata> {
  const post = await getPost(params.slug);
  if (!post) return { title: "Post not found" };

  return {
    title: post.title, // becomes "Post title | Acme" via the template
    description: post.excerpt,
  };
}

Practical rules that actually move rankings:

  • Title: ~50–60 characters, primary keyword near the beginning, unique per page. Google rewrites bad titles — don't give it a reason.
  • Description: ~150–160 characters. It doesn't affect ranking directly, but it is your ad copy in the search results and drives CTR.
  • metadataBase is mandatory — without it, relative OG image and canonical URLs break in production.
  • Deduplicate the fetch between generateMetadata and the page component with React cache() — otherwise you hit your CMS twice per request.
import { cache } from "react";

export const getPost = cache(async (slug: string) => {
  return fetchPostFromCMS(slug);
});

Checklist:

  • metadataBase set in the root layout
  • Title template defined once, pages set only their own part
  • Every page has a unique title and description
  • CMS-driven pages use generateMetadata with a cache()-wrapped fetch
  • Fallback metadata for 404 / missing-content states

Want this handled for you?

I audit and fix technical SEO on Next.js sites — indexing, performance, hreflang and AI visibility.

Technical SEO service