How to bypass cache tags for CMS preview on Vercel (Astro)?

Hey everyone,

I’m working with Astro on Vercel and using new Vercel’s tag-based cache invalidation feature (as described here: https://vercel.com/changelog/tag-based-cache-invalidation-now-available-for-all-responses).

In production, I’m tagging my responses and using those tags to cache and invalidate pages/data properly. This works great.

However, I’m now implementing a CMS preview mode, and I’m trying to find a clean way to bypass all caching entirely for preview requests, including:

  • Cache-Control headers

  • Cache tags (x-vercel-cache-tag)

The goal is that when I hit a preview route, I always get fresh data from the CMS, regardless of any previously cached responses or tags. Then invalidate those tags when I publish from my CMS.

Is there an official or recommended way to bypass cache set by Cache-Control headers and cache tags?

Curious how others are handling CMS previews with tag-based caching on Vercel on other framework than Nextjs

You can’t really bypass Vercel cache tags, but for CMS previews in Astro, the best approach is to avoid caching entirely. Use a preview flag (like ?preview=true) and fetch data with cache: 'no-store'. Even better, create a dedicated /preview route with prerender = false so pages are always server-rendered and fresh.

TL;DR:
Use SSR + no-store for previews, cache tags only for production.

One thing I’m not fully convinced about though: I don’t think the prerender boolean actually affects cache tag behavior on Vercel. From what I can tell, even with prerender = false, once a response is cached and tagged, it’s still subject to the same tag-based caching rules at the platform level.

Also, what I’m running into is that once a response is cached via tags, it seems I can’t really change cache behavior at the route level anymore (e.g. in index.astro where the data is fetched). Even if I try to switch to no-store or different Cache-Control headers for preview, the previously cached/tagged response still wins.

So it feels like: once a tag exists for a given request key, headers at the route level can’t override it anymore, which makes “bypassing” tricky for previews without fully separating the route or the request shape.