Updated April 2026
Cache-Control Headers on Vercel — vercel.json Configuration
Quick Answer
Add a headers array to vercel.json. Use "/static/(.*)" as the source for static assets with max-age=31536000, immutable. Use "/(.*)" with no-cache for HTML. API routes in /api/ should use no-store.
Vercel serves static files with its own default caching but does not set Cache-Control headers on your HTML pages or API routes. Configure them explicitly in vercel.json.
vercel.json — complete configuration
{
"headers": [
{
"source": "/static/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" },
{ "key": "Vary", "value": "Accept-Encoding" }
]
},
{
"source": "/_next/static/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
]
},
{
"source": "/api/(.*)",
"headers": [
{ "key": "Cache-Control", "value": "no-store" }
]
},
{
"source": "/(.*).html",
"headers": [
{ "key": "Cache-Control", "value": "no-cache" }
]
},
{
"source": "/((?!_next/static|static).*)",
"headers": [
{ "key": "Cache-Control", "value": "no-cache" }
]
}
]
}
Next.js — cache in route handlers
// app/api/data/route.ts
export async function GET() {
const data = await fetchData();
return Response.json(data, {
headers: {
// Public data — cache at CDN
'Cache-Control': 'public, max-age=60, stale-while-revalidate=300',
},
});
}
// Authenticated route — never cache
export async function GET(request: Request) {
return Response.json(userData, {
headers: { 'Cache-Control': 'no-store' },
});
}
Next.js App Router — fetch cache
// Force revalidation every 60 seconds
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 60 },
});
// Never cache
const data = await fetch('https://api.example.com/user', {
cache: 'no-store',
});
// Cache indefinitely (until manual revalidation)
const data = await fetch('https://api.example.com/config', {
cache: 'force-cache',
});
Edge Functions
// Edge function — set Cache-Control in response
export const config = { runtime: 'edge' };
export default function handler(req: Request) {
return new Response(JSON.stringify({ data: 'hello' }), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'public, max-age=60, stale-while-revalidate=300',
},
});
}
Check your Vercel cache headers
curl -sI https://yoursite.vercel.app/api/data | grep -i "cache\|x-vercel" # x-vercel-cache: HIT means Vercel's edge cached the response # x-vercel-cache: MISS means it hit your functionAudit your live cache headers → EdgeFix