Netlify’s CDN is the whole product, not a feature of it. Every deploy is an immutable snapshot pushed to every edge node at once, which is why a new version appears everywhere within seconds and why there is no cache to purge. Static files are cached at the edge by default; functions are not, unless you tell the CDN to with a header. The two things worth understanding are what that model gives you for free and what it charges for, because the bill is bandwidth, and bandwidth is the one number the CDN cannot make smaller.
The pages that rank for this are Netlify’s own product page, its edge functions documentation, a support thread about which plan gets the faster network, and a general overview. None of them answers the operational question: what is actually cached, how do I change it, and what happens to the bill when a page gets popular. That is this post.
Table of contents
- What a CDN is, and why Netlify’s is different
- What is cached by default, and for how long
- Controlling the cache with headers
- The two networks and what the plan changes
- Making the CDN cheaper: the bytes, not the network
- When the deploy-is-the-origin model is the wrong shape
- How this fits the rest of the stack
- FAQ
What a CDN is, and why Netlify’s is different
A content delivery network is a set of servers near your users that hold copies of your files, so a request from Sydney is answered in Sydney instead of travelling to a data centre in Virginia. The CDN content delivery post covers the general case: an origin server, edge caches in front, and cache rules deciding what each edge keeps and for how long.
Netlify’s arrangement removes the origin. There is no server of yours behind the CDN for the edge to fall back to. The deploy itself is the origin: the build produces a set of files, that set is fingerprinted and pushed to every edge node, and the edge serves it directly. The company calls this an atomic deploy, and the consequence is the property people notice first: a new deploy is live everywhere at once, there is no partially-updated state, and rolling back is republishing an older snapshot rather than rebuilding.
It also means the word cache is doing less work than usual. A traditional CDN caches a copy that may go stale. Netlify’s edge holds the current deploy, and a new deploy replaces it, so invalidation is not something you do; it is what a deploy is.
What is cached by default, and for how long
The default is simple and surprising to people used to configuring cache rules.
Static files are served from the edge with Cache-Control: public, max-age=0, must-revalidate. That looks like no caching, and in the browser it is: the browser checks with the edge on every request. But the edge answers those checks itself, with a 304 Not Modified when the file has not changed, and it holds the file until the next deploy replaces it. The result is that browsers always see the latest deploy within one request, and the edge does the work. The header is a deliberate choice so that a deploy is never hidden behind a stale browser cache.
Fingerprinted assets can be cached forever. If your build emits app.3f9a2c.js, the filename changes whenever the content does, so it is safe to tell browsers to keep it for a year with a custom header. Netlify does not add that header for you; you set it in netlify.toml or a _headers file. Most frameworks’ build output is fingerprinted, and this one header is the largest performance win most sites leave on the table.
Serverless function responses are not cached unless the function returns a cache header the CDN honours. Edge functions run at the edge, before the cache, on every request; they are for logic, not caching.
The Netlify redirects post covers how rules in _redirects and netlify.toml interact with this, since a redirect or a rewrite is evaluated at the edge before a file is served.
Controlling the cache with headers
Everything beyond the default is set with response headers, in netlify.toml or a _headers file at the publish root.
# netlify.toml
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/*.html"
[headers.values]
Cache-Control = "public, max-age=0, must-revalidate"
Three headers do most of the work. Cache-Control sets the browser’s behaviour. Netlify-CDN-Cache-Control sets the edge’s behaviour separately, for when you want the edge to hold a function response for an hour but the browser to revalidate every time. Netlify-Vary tells the edge which parts of a request, a query parameter, a cookie, a header, should produce separate cached copies, which is how a personalised or A/B-tested page is cached without leaking one user’s copy to another.
For function responses, returning Netlify-CDN-Cache-Control: public, max-age=3600, stale-while-revalidate=60 from the function itself turns a per-request compute into a cached page with a background refresh. That is the single change that moves a function-rendered site from expensive to cheap under traffic. Purging is a call to the purge API with a cache tag, and it is the only case where you invalidate anything by hand.
The two networks and what the plan changes
Netlify runs a standard edge network for most plans and a separate high-performance network with more locations and a different provider underneath, available on higher tiers. A support thread on which plan benefits from which is the third result for this keyword, and the honest reading is that for a static site with a few thousand visitors a day, the standard network is not the bottleneck. The bottleneck is a 3MB hero image.
What the plan does change, and what matters at any traffic level, is the bandwidth allowance and the price after it. The Netlify free plan post covers how to read the free tier before depending on it; the Netlify cost post covers how usage-based billing adds up. The short version for this post: bandwidth is metered per gigabyte transferred from the edge to visitors, every plan has an included allowance, and overage is charged in blocks. The CDN makes the site fast; it does not make the bytes fewer.
Making the CDN cheaper: the bytes, not the network
Because the bill is bandwidth, the work of running a cheap site on a CDN is the work of sending fewer bytes. Four things do it, in order of effect.
- Images. Serve them at the displayed size, in a modern format, and lazy-load below the fold. On most marketing sites images are 80% of the bytes, and an unoptimised gallery can cost more in bandwidth than the plan.
- Fingerprinted assets with a long cache. A returning visitor should download the JavaScript bundle once, not on every visit. The
immutableheader above is the fix. - Compression. Brotli and gzip are on by default at the edge for text; check that your build is not pre-compressing in a way that disables it.
- Cache function responses. A function that renders the same page for every visitor should render it once an hour, not once a request.
The second-order cost is build minutes, which are also metered, and a large site that rebuilds on every content change can spend those faster than bandwidth. Incremental builds and a content-driven rebuild hook rather than a rebuild-on-every-commit help.
When the deploy-is-the-origin model is the wrong shape
The model fits a site that is a set of files plus some functions. It fits less well in three situations.
A large dynamic application. If most pages are rendered per request from a database, the edge is a pass-through and you are paying CDN bandwidth prices for what is really an application server. A web service with a CDN for its static assets is the more natural fit.
Large files. Video, big downloads and generated exports through CDN bandwidth are the fastest route to an overage. Put them in object storage with its own delivery and link to them.
Predictable bills. Usage-based bandwidth is fine at low volume and stressful when a page gets shared. A host with an included allowance and a flat per-gigabyte rate after it is easier to reason about; on RunxBuild, static sites include 120GB of bandwidth a month and charge $0.10 per gigabyte after, with the same build-from-repository, custom domain and headers configuration, so the arithmetic for a popular week is one multiplication. The static sites docs cover the rest of the setup.
How this fits the rest of the stack
Netlify’s CDN serves each deploy as an immutable snapshot from every edge node, caches static files until the next deploy, and leaves functions uncached unless you set a header. Understand that model, set a long cache on fingerprinted assets, cache function responses, and shrink the images, and the network does its job. The bill is the bytes. For a sense of what a site’s bandwidth costs on a flat rate before it gets popular, the RunxBuild hosting calculator shows the static hosting and the bandwidth beyond the included 120GB as separate line items beside any services and databases the site talks to.
Useful related references:
- CDN Content Delivery: What It Actually Does for Your Bill and Your Latency
- Netlify Cost: How Usage-Based Hosting Bills Actually Add Up
- Netlify Redirects: The Rules, the Order, and the Portable Parts
- Static Sites on RunxBuild
- Custom Headers on RunxBuild
FAQ
Does Netlify use a CDN?
Yes; the CDN is the platform. Every deploy is pushed as an immutable snapshot to a global edge network, and the edge serves files directly with no origin server behind it. A new deploy replaces the previous snapshot on every node at once, which is why there is no cache to purge after deploying and why rollback is republishing an older deploy.
How long does Netlify cache files?
Static files are held at the edge until the next deploy replaces them. The default browser header is max-age=0 with must-revalidate, so browsers check with the edge on every request and receive a 304 when nothing changed. To cache fingerprinted assets in the browser for longer, set a Cache-Control header with a long max-age and immutable in netlify.toml or a _headers file.
How do I clear the Netlify cache?
For static files you do not; deploying replaces them everywhere. For cached function responses, call the purge API with a cache tag, or deploy again. If a browser appears to show old content, the cause is usually a long browser cache header on an HTML file rather than the edge, and the fix is a max-age=0 header on HTML.
Are Netlify function responses cached?
Not by default. A serverless function runs on every request unless it returns a caching header the edge honours. Returning Netlify-CDN-Cache-Control with a max-age and stale-while-revalidate from the function caches the response at the edge and refreshes it in the background, which is the main way to make a function-rendered page cheap under traffic.
How much does Netlify bandwidth cost?
Bandwidth is metered per gigabyte served from the edge, with an included allowance per plan and overage charged in blocks beyond it. The exact figures are on the pricing page and change; the operational point is that the CDN does not reduce bytes, so images, long asset caching and cached function responses are what reduce the bill.