Course outline · 0% complete

0/29 lessons0%

Course overview →

Metadata and SEO basics

lesson 7-3 · ~11 min · 24/29

Titles that sell the click

SEO (search-engine optimization, from Unit 1) is the practice of making pages easy for search engines to read and rank — for a content site it decides whether anyone finds you at all. It starts embarrassingly simple: every page needs a good <title> and meta description. In Next.js you never touch <head> directly. You export a metadata object:

// app/about/page.js
export const metadata = {
  title: "About us | Acme",
  description: "Meet the team building Acme.",
};

export default function AboutPage() { … }

Next.js renders the tags into the HTML head on the server. And because Unit 1 taught you the HTML is real (not injected by client JavaScript), crawlers actually see it. This is a core reason content sites choose server rendering.

Dynamic pages need dynamic titles

/blog/[slug] cannot hardcode one title for every post. Export a generateMetadata function instead:

// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
  const { slug } = await params;
  const post = await getPost(slug);
  return { title: post.title, description: post.summary };
}

Decode it:

  • Same await params rule as the page itself.
  • It may fetch, and thanks to the request memoization from Unit 4, fetching the same post here and in the page costs one request, not two.
  • Return shape is the same metadata object as the static version.

Title templates: brand every page once

Real sites suffix every title with the brand — 'Pricing | Acme', 'About us | Acme'. Typing "| Acme" on every page invites drift (someone forgets, someone writes - Acme). Metadata composes down the tree like layouts do, so the layout sets the pattern once:

// app/layout.js
export const metadata = {
  title: {
    template: "%s | Acme",   // %s is replaced by the child page's title
    default: "Acme",         // used when a page sets no title
  },
};

Now a page exporting title: "Pricing" renders as <title>Pricing | Acme</title>, and a page with no title falls back to Acme. One definition, every page consistent — the same reasoning that made layouts better than copy-pasting a nav bar.

Quiz

The root layout sets title: { template: "%s | Acme", default: "Acme" }. The pricing page exports metadata = { title: "Pricing" }. What does the browser tab show on /pricing?

Quiz

Why do metadata exports beat setting document.title from a useEffect in a client component?

Problem

Every post at /blog/[slug] currently shows the site-wide title 'My Blog' in search results. Which function do you export from app/blog/[slug]/page.js to give each post its own title? (function name)