obah sylva

Next.js SEO: Metadata API and Best Practices for 2026

Share this article

Use generateMetadata for dynamic pages and export const metadata for static ones, and let Next.js’s built-in bot detection handle the rest. Since Next.js 15.2, metadata for regular visitors streams in alongside the page instead of blocking it, while search engines and social crawlers still get a fully complete <head> in the very first response — so you get both speed and correct SEO tags without choosing between them.

Why This Used to Be a Real Trade-Off

Before Next.js 15.2, generateMetadata was a blocking operation: the server waited for it to resolve, built the <head>, and only then sent any HTML. If your title or description depended on a product lookup, a CMS call, or a database query, you paid for that lookup on every single request before the visitor saw anything at all. Teams routinely traded correctness for speed — hard-coding SEO tags because dynamic metadata felt too expensive to compute on the critical path.

How Streaming Metadata Actually Works

For a regular browser visitor, Next.js now sends the page’s visible content first and appends the resolved metadata as the generateMetadata call finishes, using React 19’s native ability to hoist <title> and <meta> tags into the <head> from anywhere in the component tree.

Bots are handled differently on purpose. Next.js detects HTML-limited crawlers — ones that read static markup without executing JavaScript, like Facebook’s link-preview bot or Slack’s unfurler — by user agent, and for those it falls back to the old blocking behavior: the full <head> ships in the initial response, every time. The default list covers Googlebot, Bingbot, and the major social crawlers, and it’s configurable through the htmlLimitedBots option if you need to add or remove one.

A Basic Dynamic Metadata Example

The pattern for a dynamic route stays simple:

export async function generateMetadata({ params }) {
  const { id } = await params;
  const product = await fetch(`/api/products/${id}`).then(r => r.json());
  return {
    title: product.name,
    description: product.shortDescription,
  };
}

For pages where the title and description never change, skip generateMetadata entirely and export a static metadata object instead — it’s resolved at build time, never streams, and carries zero runtime cost.

Where Streaming Metadata Can Bite You

  • Custom or unusual crawlers. If a bot isn’t on the default htmlLimitedBots list and can’t execute JavaScript, it may see incomplete metadata. Audit your traffic for crawlers you rely on — SEO tools, aggregator bots, internal scrapers — and add them explicitly if needed.
  • Buffering infrastructure. A proxy or CDN that collects the full response before forwarding it defeats the purpose of streaming entirely, whether that’s metadata or content.
  • Slow, uncached metadata sources. Streaming removes the blocking penalty for users, but a metadata function hitting an uncached database query on every request is still doing unnecessary work. Cache the underlying data, not just the symptom.

2026 Best Practices

  • Centralize brand-wide defaults — title templates, the default Open Graph image, robots policy — in a root or section layout rather than repeating them on every page.
  • Use export const metadata for anything that doesn’t depend on request-time data; reserve generateMetadata for pages where it genuinely does.
  • Treat metadata as part of your rendering architecture, not an SEO afterthought — it now interacts directly with caching, streaming, and Partial Prerendering, all covered in our Partial Prerendering breakdown.
  • If you’re pulling metadata from a headless CMS, wire generateMetadata directly to the CMS’s SEO fields — see our guide to building a blog with Next.js and a headless CMS for the content-model side of that setup.

The Bottom Line

Streaming metadata closes the gap that used to force a choice between fast pages and correct SEO tags. Use generateMetadata where your titles and descriptions genuinely depend on data, keep static metadata static, and trust the framework’s bot detection to keep search engines and social crawlers seeing the complete picture every time.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top