Next.js Docsnextjs

Next JS Metadata: Titles, Descriptions and generateMetadata

Set static metadata or use generateMetadata, add a title template, and set metadataBase so canonical and Open Graph URLs resolve. Here is the setup that works.

Automatically summarised by AI from Next.js Docs

To set Next JS metadata in the App Router, export a metadata object from a layout.js or page.js file when the values are fixed, or export a generateMetadata function when they depend on route params or fetched data. Next.js writes the title, description and other tags into the document head for you, and when the page can be prerendered they are included in the initial HTML that crawlers receive.

The static version is the one to reach for first. Import the Metadata type from 'next', export a const called metadata, and fill in fields such as title, description, openGraph, robots and alternates. Put your site-wide defaults in the root layout and let individual pages override only what differs. Fields defined deeper in the route tree take precedence over the ones above them, so a blog post page can replace the description while still inheriting everything else.

The title field deserves the most care, because it takes either a string or an object. In the root layout, set title to an object with a default and a template, for example a template of '%s | Your Brand' and a default of 'Your Brand'. A child page that exports title: 'About' then renders as 'About | Your Brand'. Two details catch people out. The template applies only to child route segments, never to the segment that defines it, so the layout itself uses the default value. And if one page needs a title with no brand suffix, use title: { absolute: '...' }, which ignores any template inherited from its parents. This matches Google's advice to put the site name at the start or end of the title, separated by a hyphen, colon or pipe, rather than repeating a long tagline everywhere.

When the values come from a database or a CMS, switch to generateMetadata. It is an async function that receives the route params and returns a Metadata object, so a post page can fetch its own record and return that post's title and description. You do not need to worry about paying for the same request twice: fetch requests made inside generateMetadata are automatically memoized across generateMetadata, layouts, pages and server components, and for data access that does not use fetch you can wrap the call in React's cache function. Resolving generateMetadata is part of rendering the page, so keep it fast and fetch only the fields you need.

Set metadataBase once, in the root layout, as a new URL built from an environment variable that holds your production origin. Fields that require absolute URLs, such as Open Graph images and the canonical link, can then be written as relative paths and Next.js composes the full address for you. Without it, relative values have nothing to resolve against. A canonical for each post is a single line, alternates: { canonical: '/blog/your-slug' }, set inside that page's generateMetadata so every page points at itself.

One behaviour is easy to miss on dynamic pages. Next.js can stream metadata after the initial HTML has been sent, which keeps the first paint quick. The documentation explains that it detects crawlers that need metadata in the head by checking the User-Agent header and serves them blocking metadata instead. You can adjust which user agents get that treatment with the htmlLimitedBots option in next.config, and disabling streaming entirely is possible if you want the simplest guarantee. For a page that is prerendered, none of this applies, because the tags are already in the HTML.

Writing good values matters as much as setting them. Google says title links are generated automatically from several signals, including the h1 and on-page text, and that it may replace your title when it looks half-empty, obsolete or inaccurate. It states no limit on title length, but long titles are truncated to fit the device width, so lead with what matters. For descriptions, Google builds snippets mostly from the page itself and only sometimes uses the meta description, when it describes the page better. Make each one unique, summarise the actual page, and avoid keyword lists. Generating them programmatically is fine for large sites as long as the results read naturally.

A short checklist keeps the setup honest. Define a title template and a default in the root layout. Set metadataBase from your production origin. Give every dynamic page a generateMetadata that returns its own title, description and canonical. Use title.absolute only when you have a reason. Move colour and viewport settings out of metadata: the themeColor field is deprecated in favour of generateViewport. Finally, view the page source rather than the browser tab to confirm the tags are present in the HTML that Google will fetch, then request a recrawl in Search Console if you changed titles on pages that already rank.

nextjs · Next.js Docs · Published 00:03 · 13 Oct 2026

Read the original ↗

Related stories