Fixing Meta Tags Overwritten During Hydration

A server-rendered page can ship the correct <title> and meta description, then lose them a moment later: during hydration the client component mounts with default metadata — before the route’s data resolves — and overwrites the server’s tags. If a crawler captures the DOM in that window, it indexes the defaults. This is a hydration-timing bug, and it is the core failure that avoiding metadata hydration pitfalls addresses.

Step-by-step fix

  1. Confirm the overwrite. Compare the head in the server response with the head after hydration.

    // In the console right after load:
    document.title // is it the route's title, or a default like "My App"?
  2. Hydrate metadata from the same data the server used. The client’s first render must compute the same title/description, so hydration is a no-op for the head.

    // ❌ Client mounts with a default, then updates after fetch → overwrite + flash
    useEffect(() => { document.title = data?.title ?? 'My App'; }, [data]);
    
    // ✅ Title derived from data present at first render (passed from the server)
    function ProductMeta({ product }) {
      useServerInsertedHead(() => <title>{product.name}</title>);
      return null;
    }
  3. Do not render placeholder meta on the first client pass. If data is not ready, render nothing for the head rather than a default that overwrites the server value.

  4. Mutate, don’t replace, the tags so hydration reconciles cleanly instead of tearing down and rebuilding the head.

Validation

  • document.title after load equals the server-rendered title, with no flash.
  • GSC URL Inspection rendered HTML shows the correct title and description.
  • No console hydration warning for the metadata components.
  • Throttled CPU reload shows no visible default-then-correct title flash.

Reference

// Pass server data to the client so first render matches — no overwrite
export function Head({ meta }) {
  // meta is serialized from the server render and available on first client render
  return (
    <>
      <title>{meta.title}</title>
      <meta name="description" content={meta.description} />
      <link rel="canonical" href={meta.canonical} />
    </>
  );
}

Frequently Asked Questions

Why do my meta tags reset to defaults after the page loads? The client re-renders during hydration with default metadata before the route’s real data is available, overwriting the correct server-rendered tags. The fix is to compute the same metadata on the client from the same data the server used, so the first client render matches.

Does a brief meta flash hurt SEO? If a crawler snapshots the DOM during the default-value window, it can index the wrong title or description. Even when it does not, the flash signals that client metadata is not aligned with the server, which is a fragile state worth fixing.

← Back to Avoiding Metadata Hydration Pitfalls