Cache the HTML Too
- Date
A lot of web frameworks and platforms bury the single easiest way to make a site faster and cheaper: CDN caching. We spend enormous effort shaving milliseconds off server-side rendering, picking the fastest meta-framework, optimizing database queries, and then skip past the one move that beats all of it. Just save the result. There’s no reason to repeat the same work on every single request.
The fastest request is the one your server never sees.
HTML is cacheable too
Most CDNs make this trivial, but the default trips people up. Cloudflare, Fastly, CloudFront, Vercel’s edge: they all cache your static assets (CSS, JS, images, fonts) out of the box. What they do not cache by default is HTML. As Cloudflare’s docs put it plainly: “The Cloudflare CDN does not cache HTML by default.”
That’s the part people miss. Caching media feels obvious, but caching pages feels dangerous. Yet a huge fraction of the HTML you serve is identical for every visitor, and there’s no reason to render it fresh each time.
Turning it on is mostly a one-liner. The mechanism across every CDN is the Cache-Control header: s-maxage controls how long the CDN holds the response, and stale-while-revalidate lets it serve the stale copy instantly while refreshing in the background. On Cloudflare you can also do it without touching your app, via a Cache Rule that marks matching URLs as eligible for cache.
One real caveat: “cache everything” means everything. If you blanket-cache HTML, you can hand one user’s logged-in page to the next visitor. So scope it: exclude anything with an auth cookie, exclude your dashboard, cache the public pages. Anything that sets Set-Cookie, private, or no-store is skipped automatically, but you should still be deliberate about it.
How much of your site actually needs to be fresh?
This is the question worth asking before you reach for anything fancier. Your blog, your marketing pages, your docs, your product listings… how often do they really change? Sure, modern frameworks render pages fast. But “fast to render on every request” will always lose to “already rendered, sitting at an edge node 20ms from the user.” Static beats dynamic, and a cache turns dynamic into static for the 99% of requests where nothing changed.
A note on framework caching
Frameworks have their own caching layers, and it’s easy to conflate them with CDN caching. Next.js is the instructive case because its caching model is famously confusing.
Next.js has several distinct caches: Request Memoization (dedupes calls within a single render), the Data Cache (persists fetch results across requests), the Full Route Cache (server-side), and the Router Cache (client-side). The Full Route Cache serves fully rendered static pages straight from cache: at build time Next.js renders static routes to HTML plus the RSC payload, and serves that cached output instead of re-rendering per request. That’s exactly the static-serving behavior you want.
Server Actions are not cached. They use POST and are mutations by design; Next.js only ever memoized GET-style data fetches. Actions can trigger invalidation via revalidatePath / revalidateTag, but they’re never served from cache.
Worth knowing too: Next.js 15 flipped the defaults toward less implicit caching: fetch is no-store by default now, and GET route handlers aren’t cached by default. The framework is leaning away from caching-by-magic, which makes the case for owning your caching at the CDN layer even stronger.
None of this means Next.js is bad at caching. The point is that framework caches and CDN caches solve overlapping but different problems, and the CDN layer is the portable one. It works the same no matter what you build with, and it’s hard to beat for the effort it takes. Reach for it first.
References
- Cloudflare: default cache behavior — what gets cached out of the box, and what doesn’t
- Cloudflare: “Cache Everything” via Cache Rules
- Next.js caching guide — the four cache layers, explained
- Next.js 15 release notes — the caching default changes
- MDN:
Cache-Control—s-maxage,stale-while-revalidate, and friends