skillZs
LIVE SKILL TAGS
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
REAL INSTALL DATA
← back to all skills
netlify/context-and-tools1k installs

netlify-caching

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.

How do I install this agent skill?

npx skills add https://github.com/netlify/context-and-tools --skill netlify-caching
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill is a technical documentation guide for configuring Netlify CDN caching and contains no malicious code or security vulnerabilities.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

  • Runlayerpass

    1 file scanned · No issues

What does this agent skill do?

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.

Only GET requests are cached. Netlify's CDN caches responses to GET requests only. Responses to POST, PUT, PATCH, DELETE, and other non-GET methods are never cached, no matter what cache headers you set on them. If a response needs to be CDN-cacheable, expose it on a GET route (put the inputs in the URL/query string) — you cannot make the CDN cache a mutating POST endpoint by adding cache headers.

Cache-Control Headers

Three headers control caching, from most to least specific:

HeaderWho sees itUse case
Netlify-CDN-Cache-ControlNetlify CDN only (stripped before browser)CDN-only caching
CDN-Cache-ControlAll CDN caches (stripped before browser)Multi-CDN setups
Cache-ControlBrowser and all cachesGeneral caching

Common Patterns

// 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):

# 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:

return new Response(body, {
  headers: {
    "Netlify-Cache-Tag": "product,listing",
    "Netlify-CDN-Cache-Control": "public, s-maxage=86400",
  },
});

Purge by tag:

import { purgeCache } from "@netlify/functions";

export default async () => {
  await purgeCache({ tags: ["product"] });
  return new Response("Purged", { status: 202 });
};

Purge entire site:

await purgeCache();

purgeCache() picks up the site ID and credentials automatically only when it runs inside a deployed Netlify Function. Called from anywhere else — a local script, a CI job, a build step, or any code outside the Netlify Functions runtime — it has no ambient credentials, and you must pass a Netlify personal access token (and the site ID). Read the token from an environment variable; never hardcode it:

await purgeCache({
  token: process.env.NETLIFY_PURGE_TOKEN, // a Netlify personal access token, from env
  siteID: process.env.NETLIFY_SITE_ID,
  tags: ["product"],
});

Netlify-Cache-Tag is purge-only: tagged responses are still cleared by automatic deploy-based invalidation like everything else. The tag only lets you purge them on demand between deploys.

Surviving deploys with Netlify-Cache-ID

To keep a cached response across deploys, set a Netlify-Cache-ID header. A response carrying it is excluded from automatic deploy-based invalidation — it persists across deploys and clears only on explicit purge. The Netlify-Cache-ID value also auto-registers as a purge tag, so you purge it by that same id:

return new Response(body, {
  headers: {
    "Netlify-Cache-ID": "catalog",
    "Netlify-CDN-Cache-Control": "public, s-maxage=86400",
  },
});
import { purgeCache } from "@netlify/functions";

// Purge by the same id — it doubles as a purge tag.
await purgeCache({ tags: ["catalog"] });

Cache Key Variation

Netlify-Vary controls what creates separate cache entries. Each directive names a dimension — query, header, cookie, country, or language — followed by an enumerated, pipe-separated list of the values to key on:

return new Response(body, {
  headers: {
    "Netlify-Vary": "cookie=ab_test|is_logged_in",
  },
});
  • query=param1|param2 — key on the named query parameters
  • header=X-Custom — key on the named request header
  • cookie=ab_test|is_logged_in — key on the named cookies
  • country=us|de — serve a distinct cached entry to visitors from the listed countries (two-letter, lowercase ISO country codes)
  • language=en|fr — key on the listed Accept-Language values

Combine dimensions by separating directives with commas — e.g. Netlify-Vary: query=theme, cookie=plan keys the cache on both the theme query parameter and the plan cookie. Always enumerate the specific values; keying on an entire dimension (for example a bare Vary: Cookie) fragments the cache into a separate entry per unique visitor.

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.

The full query string is part of the cache key by default. With no Netlify-Vary: query= directive, every distinct query string is cached as a separate entry — so appending tracking or marketing params (?utm_source=…, fbclid, and the like) silently fragments the cache into many near-duplicate entries and lowers the hit rate, even when those params don't change the response. Add Netlify-Vary: query=<names> listing only the parameters that actually affect the output; the CDN then keys on just those and ignores all other query params, collapsing the variants onto one cache entry.

Local Development

netlify dev does not emulate the CDN cache. Header-based CDN caching is only observable on a deployed site: locally, cache headers pass through untouched, nothing is stored in or served from the CDN cache, Cache-API reads return no persisted entries, and the Cache-Status response header is absent. A "cache miss every time" on localhost is expected, not a bug — you cannot validate Netlify-Vary keying, cache tags, durable cache, or purge behavior locally. Verify caching on a deployed URL instead (a Deploy Preview or production) and read its Cache-Status header.

Debugging

Check the Cache-Status response header. Netlify emits it in the RFC 9211 format — one entry per named cache layer the request passed through, not a bare HIT/MISS:

Cache-Status: "Netlify Edge"; fwd=miss, "Netlify Durable"; hit; ttl=3600
  • A named layer ("Netlify Edge", "Netlify Durable") with hit — served from that cache
  • fwd=miss — the entry was not in that layer, so the request was forwarded onward
  • ttl=… — remaining freshness (seconds) for a hit

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)

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/netlify/context-and-tools/netlify-caching">View netlify-caching on skillZs</a>