Skip to content

Manage cache tags for external origins

Learn how to use cache tags to optimally serve fresh content on Vercel when content from your external origin changes

Vercel
5 min read
Last updated March 25, 2026

This guide shows you how content served from an external origin through Vercel’s CDN can be cached and selectively invalidated so it is only regenerated when data changes.

Vercel's CDN improves performance and security when proxying requests to external origins, or origins that are hosted somewhere other than Vercel. The CDN reduces latency by caching content close to the user in all Vercel Regions worldwide, while the Vercel Firewall protects against threats like DDoS attacks, bot traffic, and malicious requests before they reach your servers.

Users want to see content delivered very quickly from anywhere in the world. Caching improves performance by storing and serving the content close to users, but the content also needs to be fresh and updated as soon as data changes. When data changes, you have two options for how to make sure the content is fresh:

  1. Purge all cached content - This option is too coarse and hurts performance and costs for unchanged content. Users have to make a request back to the origin on the next request which will be slow.
  2. Purge specific content - This option requires assigning tags to specific pages that are updated at the same time. Content can be invalidated so that a stale page is served to the user on the next request while the cache is refreshed in the background.

Cache tags solve this by letting you organize cached responses into groups that you can invalidate at the same time. Other requests that are tagged differently are unaffected. Cache tags may also be referred to as surrogate keys on other platforms.

The rest of this guide will walk you through how to use and invalidate cache tags in your application.

A rewrite routes a request to a different destination without changing the URL in the browser. Unlike redirects, the user won't see the URL change.

To set up a rewrite, configure the vercel.json with the following code:

vercel.json
{
"rewrites": [
{
"source": "/api/(.*)",
"destination": "https://api.yourdomain.com/api/$1"
}
]
}

The flow for a request will be:

  1. User requests yourdomain.com/api/products/123
  2. Vercel CDN checks for cached content
  3. If not cached, Vercel fetches from api.yourdomain.com/api/products/123
  4. Your server responds with content and cache tags
  5. Vercel caches the response with those tags

Configure your server to set the Vercel-Cache-Tag header:

server.js
app.get('/api/products/:id', async (req, res) => {
const product = await getProduct(req.params.id);
const tags = [
`product-${req.params.id}`,
`category-${product.category}`,
'products'
];
if (product.featured) {
tags.push('homepage');
}
res.setHeader('Vercel-Cache-Tag', tags.join(','));
res.setHeader('Cache-Control', 's-maxage=3600, max-age=60, stale-while-revalidate=86400');
res.json(product);
});

What each tag does:

  • product-123 - Invalidate when this specific product changes
  • category-electronics - Invalidate when any product in this category changes
  • products - Invalidate when the product catalog changes
terminal
npm install -g vercel
vercel login

If you have multiple teams, make sure that you have selected the right team:

terminal
vercel teams switch your-team-name

Now that the Vercel CDN is caching content, you can selectively invalidate specific cache tags to see new content being picked up. When cache tags are invalidated, the next request will return the stale content while the Vercel CDN is refreshing the cache contents in the background. This maintains performance while making sure that subsequent requests get the fresh content.

There are different ways that content can be invalidated on Vercel

Cache tags can be invalidated directly in code if you have a function or webhook that runs when data changes.

Option 1: Direct invalidation in your update function

The invalidateByTags function can be called from server side code in the same project that the tag is defined in.

update-product.js
import { Vercel } from "@vercel/sdk";
const vercel = new Vercel({
bearerToken: "<YOUR_BEARER_TOKEN_HERE>",
});
async function updateProduct(id, data) {
await database.products.update(id, data);
const tags = [
`product-${id}`,
`category-${data.category}`,
'products'
];
if (data.featured) {
tags.push('homepage');
}
await vercel.edgeCache.invalidateByTags({
projectIdOrName: "<value>",
teamId: "team_1a2b3c4d5e6f7g8h9i0j1k2l",
slug: "my-team-url-slug",
requestBody: { tags },
});
return { success: true, invalidated: tags };
}

Option 2: CMS webhook handler

If data is updated in an external CMS, you can create a webhook route handler to receive the event when data changes and choose which tags to invalidate.

api/webhooks/cms-updated.js
import { Vercel } from "@vercel/sdk";
const vercel = new Vercel({
bearerToken: "<YOUR_BEARER_TOKEN_HERE>",
});
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const { event_type, resource_id, resource_type, data } = req.body;
let tags = [];
if (resource_type === 'product') {
tags = [
`product-${resource_id}`,
`category-${data.category}`,
'products'
];
if (data.featured) tags.push('homepage');
} else if (resource_type === 'category') {
tags = [`category-${resource_id}`, 'categories'];
}
if (tags.length === 0) {
return res.status(400).json({ error: 'No tags to invalidate' });
}
try {
await vercel.edgeCache.invalidateByTags({
projectIdOrName: "<value>",
teamId: "team_1a2b3c4d5e6f7g8h9i0j1k2l",
slug: "my-team-url-slug",
requestBody: { tags },
});
res.json({ success: true, invalidated: tags });
} catch (error) {
res.status(500).json({ error: 'Cache invalidation failed' });
}
}

The Vercel CLI can also be used to invalidate at any time.

terminal
# Single tag
vercel cache invalidate --tag product-123
# Multiple tags (comma-separated)
vercel cache invalidate --tag "product-123,homepage,electronics"

Purge all cache:

Invalidate is the recommended option, but the Vercel CLI can also purge all cache content. This option isn’t recommended since it causes a blocking request to the external origin, but it can be used when all content must be updated.

terminal
# Purge all CDN cache
vercel cache purge --type cdn
# Purge all cache types
vercel cache purge

If you are not able to set cache tags in the response from your external origin, you can still set cache tags on Vercel using routing rules.

Setting cache tags in vercel.json

vercel.json
{
"routes": [
{
"source": "/products/electronics/(.*)",
"destination": "https://api.example.com/api/products/$1",
"headers": {
"Vercel-Cache-Tag": "product-$1,category-electronics"
}
}
]
}

Setting cache tags from the CLI

Routing rules to set cache tags can also be set using the CLI to add routing rules without requiring you to change any code. Use the vercel routes CLI command:

terminal
# Add cache tags for the category and product ID when rewriting the request to the external origin
vc routes add "Electronics" --src "/products/electronics/:id" --src-syntax path-to-regexp --action rewrite --dest "https://api.example.com/api/products/:id" --set-response-header 'Vercel-Cache-Tag=product-$1,category-electronics'

Cache tags can be incrementally added to your application and optimized based on usage patterns and how often data is updated. Learn more about caching in the Vercel CDN Cache documentation.

Was this helpful?

supported.

Read related documentation

No related documentation available.

Explore more guides

No related guides available.