Metadata

The Metadata Object and metadataBase

Static metadata is an object exported from a layout or page, typed with Metadata.

Site-wide metadata in the root layoutShell
export const metadata: Metadata = {
  metadataBase: new URL("https://example.com"),
  title: { default: "Bookshelf", template: "%s | Bookshelf" },
  alternates: { canonical: "/" },
  openGraph: { type: "website", siteName: "Bookshelf", locale: "en_US", url: "/" },
  twitter: { card: "summary_large_image", site: "@example" },
  robots: { index: true, follow: true, googleBot: { "max-image-preview": "large" } },
};

The home page adds only its own title and description. Requesting /, script tags removed:

Output of 76
<meta charSet="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Every book we have read</title>
<meta name="googlebot" content="max-image-preview:large"/>
<link rel="canonical" href="https://example.com"/>
<meta property="og:site_name" content="Bookshelf"/>

Charset and viewport arrive unasked. The layout's openGraph survived only because the page did not declare it: merging is one key deep, so a page setting openGraph: { title: "Blog" } discards the layout's siteName and locale instead of patching them — keep shared fragments in a module and spread them. Titles are the exception: title.template applies to descendants only, never to the segment declaring it (hence title.default), and a child's title.absolute opts out of an inherited template.

metadataBase lets URL fields below it be written as paths, so canonical: "/" came back absolute; without it a relative URL is a build error. Set it from an environment variable so previews do not advertise production canonicals. Both are Server Component exports: "use client" on a page exporting metadata fails the build.