netlify-caching
$
npx mdskill add openai/plugins/netlify-cachingControl Netlify's CDN behavior by setting precise cache headers for assets and functions.
- Configuring cache headers like Cache-Control and Netlify-CDN-Cache-Control for optimal delivery.
- Integrates with Netlify's build environment and Edge Functions for response manipulation.
- Determines caching strategy based on required freshness, stale-while-revalidate, or purge needs.
- Provides code examples and documentation on setting various caching directives for implementation.
SKILL.md
.github/skills/netlify-cachingView on GitHub ↗
---
name: netlify-caching
description: Guide for controlling caching on Netlify's CDN. Use when configuring cache headers, setting up stale-while-revalidate, implementing on-demand cache purge, or understanding Netlify's CDN caching behavior. Covers Cache-Control, Netlify-CDN-Cache-Control, cache tags, durable cache, and framework-specific caching patterns.
---
# Caching on Netlify
## Default Behavior
**Static assets** are cached automatically:
- CDN: cached for 1 year, invalidated on every deploy
- Browser: always revalidates (`max-age=0, must-revalidate`)
- No configuration needed
**Dynamic responses** (functions, edge functions, proxied) are **not cached by default**. Add cache headers explicitly.
## Cache-Control Headers
Three headers control caching, from most to least specific:
| Header | Who sees it | Use case |
|---|---|---|
| `Netlify-CDN-Cache-Control` | Netlify CDN only (stripped before browser) | CDN-only caching |
| `CDN-Cache-Control` | All CDN caches (stripped before browser) | Multi-CDN setups |
| `Cache-Control` | Browser and all caches | General caching |
### Common Patterns
```typescript
// Cache at CDN for 1 hour, browser always revalidates
return new Response(body, {
headers: {
"Netlify-CDN-Cache-Control": "public, s-maxage=3600, must-revalidate",
"Cache-Control": "public, max-age=0, must-revalidate",
},
});
// Stale-while-revalidate (serve stale for 2 min while refreshing)
return new Response(body, {
headers: {
"Netlify-CDN-Cache-Control": "public, max-age=60, stale-while-revalidate=120",
},
});
// Durable cache (shared across edge nodes, serverless functions only)
return new Response(body, {
headers: {
"Netlify-CDN-Cache-Control": "public, durable, max-age=60, stale-while-revalidate=120",
},
});
```
### Immutable Assets
For fingerprinted files (hash in filename):
```toml
# netlify.toml
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
```
## Cache Tags and On-Demand Purge
Tag responses for selective cache invalidation:
```typescript
return new Response(body, {
headers: {
"Netlify-Cache-ID": "product,listing",
"Netlify-CDN-Cache-Control": "public, s-maxage=86400",
},
});
```
Purge by tag:
```typescript
import { purgeCache } from "@netlify/functions";
export default async () => {
await purgeCache({ tags: ["product"] });
return new Response("Purged", { status: 202 });
};
```
Purge entire site:
```typescript
await purgeCache();
```
Responses with `Netlify-Cache-ID` are **excluded from automatic deploy-based invalidation** — they must be purged explicitly.
## Cache Key Variation
Customize what creates separate cache entries:
```typescript
return new Response(body, {
headers: {
"Netlify-Vary": "cookie=ab_test|is_logged_in",
// Other options: query=param1|param2, header=X-Custom, country=us|de, language=en|fr
},
});
```
## Framework-Specific Caching
### Next.js
ISR uses Netlify's durable cache automatically (runtime 5.5.0+). `revalidatePath` and `revalidateTag` trigger cache purge.
### Astro / Remix
Full control over cache headers in server routes. Set `Netlify-CDN-Cache-Control` in responses for CDN caching.
### Nuxt
Default Nitro preset handles caching. ISR-style patterns use `routeRules` with `swr` or `isr` options.
### Vite SPA
Static assets are cached by default. API responses from Netlify Functions need explicit cache headers.
## Debugging
Check the `Cache-Status` response header:
- `HIT` — served from cache
- `MISS` — generated fresh
- `REVALIDATED` — stale content was revalidated
## Constraints
- Basic auth disables caching for the entire site
- Durable cache is serverless functions only (not edge functions)
- Same URL must return identical `Netlify-Vary` headers across responses
- Deploy invalidation is scoped to deploy context (production vs preview)