Next.js Metadata Not Updating? Here's Why
Not sure if it's your code or a cache?
Check it free with Proovd. It shows exactly what metadata your live URL is serving right now, independent of any platform's own cache.
Quick Answer
- Most cases are Next.js's own data cache or a CDN cache serving stale HTML, not a code bug
- generateMetadata in a Server Component only re-runs when its underlying fetch cache revalidates
- The rest are usually the platform's cache (Facebook, LinkedIn, etc.), not Next.js. Check both before assuming either
Reproducible Example
This looks correct but will keep serving stale metadata after a content change:
export async function generateMetadata({ params }) {
const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(r => r.json());
return {
title: post.title,
openGraph: {
images: [post.image],
},
};
}
The fetch call here is cached by Next.js's Data Cache by default. If post.title or post.image changes in your CMS, this function won't see the new value until the cache revalidates. With no explicit strategy, that can mean not until the next full build.
Why Your Metadata Isn't Updating
The underlying fetch is cached
By default, fetch() inside generateMetadata is cached indefinitely in the App Router. Fix by setting an explicit revalidation window:
const post = await fetch(url, { next: { revalidate: 60 } }).then(r => r.json());
Or opt out of caching entirely for that request:
const post = await fetch(url, { cache: "no-store" }).then(r => r.json());
The route is statically generated
If the route uses generateStaticParams with no revalidation configured, the entire route, metadata included, is baked in at build time. Adding export const revalidate = 3600; at the page level forces periodic regeneration.
A CDN or edge cache is serving the old HTML
Even if your build is correct, Vercel's Edge Network, Cloudflare, or another CDN in front of your app can serve a cached HTML response that predates your fix. Check response headers:
curl -I https://yoursite.com/blog/post-slug
Look for x-vercel-cache: HIT or a similar CDN header. A HIT means you're looking at a cached copy, not your latest deploy.
opengraph-image.ts isn't picking up new data
If you're using the file-based opengraph-image.ts convention, Next.js generates a static image at build time by default. Dynamic content inside it is subject to the same caching rules as any other Server Component, so add explicit revalidation if it needs to stay fresh.
It's actually the platform's cache, not yours
The most common false alarm. Your app can be serving perfectly fresh metadata while Facebook, LinkedIn, or Slack are still showing a preview they cached days ago. Confirm what your server is sending before touching any Next.js code. See our guide to clearing OG cache on every platform.
Step-by-Step Fix Guide
- Run
curl -s https://yoursite.com/page | grep -i "og:"to see what your server actually sends - Check for a CDN cache
HITheader withcurl -I https://yoursite.com/page - Add explicit
revalidateorcache: "no-store"to fetches insidegenerateMetadata - Force a fresh deploy to rule out a stale build cache
- Verify the live result with Proovd
Next.js vs. Other Frameworks
| Framework | Common cause | Fix pattern |
|---|---|---|
| Next.js (App Router) | Cached fetch inside generateMetadata, or static build with no ISR | revalidate option or cache: "no-store" |
| Astro | Client-only meta tag injection instead of static frontmatter/SSR | Move tags into the page's static output |
| SvelteKit | Meta tags set only client-side, not in the server load function | Load meta values server-side, pass to the head |
Quick Fix Checklist
- Confirmed raw HTML output has the correct tags (not just the browser DOM)
- Added explicit revalidate or cache: "no-store" to fetches inside generateMetadata
- Checked CDN/edge cache headers for a stale HIT
- Confirmed whether the route is fully static with no ISR
- Ruled out the social platform's own cache as the real cause
- Verified the final live output with Proovd
Frequently Asked Questions
Why does my og:image update in the browser but not on Facebook or LinkedIn?
Your Next.js app is likely already serving the correct tag. The platform is showing a copy it cached before your fix. Use that platform's own cache-refresh tool rather than changing more code.
Does revalidate: 0 disable caching entirely?
Setting revalidate: 0 effectively forces dynamic rendering for that fetch on every request, similar to cache: "no-store". Use it sparingly since it removes the performance benefit of caching.
Related Articles
Confirm what your Next.js app is actually serving
Check your live metadata free with Proovd. It shows exactly what's in your HTML right now, independent of any platform's cache.