opdeck / blog / your-worker-can-now-have-its-own-cache-in-front-of-it

How to Set Up a Cache for Your Worker in Front of It

July 9, 2026 / OpDeck Team
HTTP CachingWeb OptimizationPerformanceCaching HeadersWeb Development

How HTTP Caching Headers Actually Work (And Why They Matter More Than Ever)

If you've spent any time optimizing web applications, you've encountered HTTP caching headers. They're deceptively simple-looking strings in an HTTP response, yet they control one of the most powerful performance mechanisms available to developers. With Cloudflare's recent announcement of Workers Cache — a regionally tiered cache that sits directly in front of Worker entrypoints, configured entirely through standard HTTP headers — it's worth taking a deep step back and understanding exactly how these headers work, what they mean, and how to use them correctly.

Because here's the thing: most developers use caching headers reactively, copying configurations from Stack Overflow or framework defaults without fully understanding what they're doing. That leads to bugs that are notoriously hard to diagnose: stale content served to users, cache poisoning vulnerabilities, or worse — no caching at all when you thought there was.

Let's fix that.


What HTTP Caching Headers Are Actually Doing

At their core, HTTP caching headers are instructions. They tell browsers, CDN edge nodes, reverse proxies, and now Worker-level caches exactly how to store, validate, and serve responses. The two most important directives live in the Cache-Control header, which replaced the older Expires header in HTTP/1.1.

Here's a minimal example:

HTTP/1.1 200 OK
Cache-Control: max-age=3600, public
Content-Type: application/json

This tells any cache in the chain: "You can store this response and serve it for up to 3600 seconds (one hour) without checking back with the origin."

But that single line hides a lot of complexity. Let's break down the most important directives.

max-age vs s-maxage

max-age applies to all caches — the browser's private cache and any shared caches (CDNs, proxies). s-maxage applies only to shared caches and overrides max-age for those layers.

Cache-Control: max-age=60, s-maxage=86400

This configuration tells the browser to cache for 60 seconds, but allows your CDN or edge cache to hold onto the response for 24 hours. This is extremely useful for API responses where you want relatively fresh data in the browser but want to protect your origin from thundering herd scenarios.

public vs private

public explicitly permits shared caches to store the response, even if the request included authentication headers. private restricts caching to the end-user's browser only — no CDN, no proxy should store it.

Cache-Control: private, max-age=300

Use private for personalized responses: user dashboards, account pages, anything containing user-specific data. Failing to mark these as private can result in one user's data being served to another — a serious security issue.

no-cache vs no-store

These two are frequently confused:

  • no-cache does not mean "don't cache." It means "always revalidate with the origin before serving from cache." The response can still be stored.
  • no-store means "never store this response anywhere, ever."
# Revalidate every time, but can store the response
Cache-Control: no-cache

# Never store this response
Cache-Control: no-store

For sensitive data like banking information or medical records, no-store is the right choice. For dynamic content that changes frequently but doesn't contain sensitive information, no-cache with proper ETag or Last-Modified headers gives you the best of both worlds.


Validation: ETags and Last-Modified

Storing a cached response is only half the picture. The other half is revalidation — checking whether a stored response is still fresh without downloading the entire response body again.

ETags

An ETag is an opaque identifier (typically a hash of the content) that the server generates for a specific version of a resource:

HTTP/1.1 200 OK
Cache-Control: no-cache
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Content-Type: text/html

When the cache revalidates, it sends the ETag back to the server in an If-None-Match header:

GET /index.html HTTP/1.1
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

If the content hasn't changed, the server responds with 304 Not Modified and no body — saving bandwidth. If it has changed, the server returns the new content with a new ETag.

Last-Modified

Last-Modified works similarly but uses timestamps instead of content hashes:

HTTP/1.1 200 OK
Last-Modified: Tue, 15 Oct 2024 12:00:00 GMT
Cache-Control: max-age=0, must-revalidate

The revalidation request uses If-Modified-Since:

GET /styles.css HTTP/1.1
If-Modified-Since: Tue, 15 Oct 2024 12:00:00 GMT

ETags are generally preferred over Last-Modified because they're more precise — timestamps can have one-second granularity issues, and some systems modify file timestamps without changing content.


Stale-While-Revalidate: The Best Pattern You're Probably Not Using

One of the most powerful (and underused) caching directives is stale-while-revalidate. It allows a cache to serve a stale response immediately while simultaneously fetching a fresh one in the background:

Cache-Control: max-age=60, stale-while-revalidate=3600

This configuration means: "Serve fresh for 60 seconds. After that, serve stale for up to 3600 seconds while revalidating in the background."

The practical effect is that users almost never wait for a cache miss. The first user after the TTL expires gets the stale response instantly, and the cache refreshes in the background. The next user gets the fresh response.

This pattern is particularly powerful at the edge — exactly the scenario Cloudflare's Workers Cache is designed for. When your Worker sits behind a regional cache configured with stale-while-revalidate, you get low-latency responses for the vast majority of requests with origin protection built in.

Similarly, stale-if-error lets you serve stale content if the origin returns an error:

Cache-Control: max-age=3600, stale-if-error=86400

This is essentially a free resilience mechanism — if your origin goes down for up to 24 hours, users keep getting (slightly stale) responses instead of error pages.


Vary: The Header That Controls Cache Segmentation

The Vary header tells caches that the response may differ based on specific request headers. This is critical for content negotiation:

HTTP/1.1 200 OK
Vary: Accept-Encoding
Cache-Control: public, max-age=86400

This tells caches to store separate versions of the response for different Accept-Encoding values — so gzip-compressed and uncompressed versions are cached separately.

Common Vary use cases:

# Different responses for different content types
Vary: Accept

# Different responses for different languages
Vary: Accept-Language

# Different responses for mobile vs desktop (use carefully)
Vary: User-Agent

Warning: Vary: User-Agent is almost always a bad idea. There are thousands of distinct User-Agent strings, which effectively defeats caching entirely. If you need device-specific responses, use separate URLs or cookies instead.


Cache-Control in Practice: Real-World Configurations

Here are some concrete configurations for common scenarios:

Static Assets with Content Hashing

If your build process generates hashed filenames (like main.a3f9c2.js), you can cache forever:

Cache-Control: public, max-age=31536000, immutable

The immutable directive tells the browser not to revalidate even on explicit refresh — a significant performance win for returning visitors.

HTML Pages

HTML pages typically need more careful handling since they reference other assets:

Cache-Control: public, max-age=0, must-revalidate

Or with stale-while-revalidate for better perceived performance:

Cache-Control: public, max-age=300, stale-while-revalidate=3600

API Responses

For public API responses that change infrequently:

Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=600

For authenticated API responses:

Cache-Control: private, no-cache
ETag: "abc123"

Webhook Endpoints and Mutation Endpoints

These should never be cached:

Cache-Control: no-store

How Edge Caches Differ from Browser Caches

Understanding that there are multiple caches in the chain is crucial. A typical request passes through:

  1. Browser cache — local to the user's device, private
  2. CDN/Edge cache — shared, geographically distributed
  3. Origin server — your application

Each layer can have different TTLs via s-maxage. The edge cache layer is where the most interesting optimization happens, because it protects your origin from traffic spikes while staying geographically close to users.

With Cloudflare's Workers Cache specifically, there's now a cache layer that sits in front of your Worker code itself. This means even the compute cost of running your Worker can be avoided for cacheable responses — the cache returns the response before your Worker code even executes.

This changes how you think about cache headers in your Worker responses. Previously, you might have set aggressive cache headers to help downstream CDN layers. Now, those same headers directly control whether your Worker runs at all for subsequent requests.

You can inspect what cache headers your server is actually sending (versus what you think it's sending) using the Cache Inspector tool — it shows the raw HTTP headers and helps identify misconfigurations like missing Cache-Control headers or conflicting directives.


Security Considerations for Caching

Caching headers aren't just a performance concern — they have real security implications.

Never Cache Sensitive Responses

Any response containing authentication tokens, personal data, or session information must use Cache-Control: private, no-store. A misconfigured shared cache serving one user's authenticated response to another user is a serious data breach.

Cache Poisoning

Cache poisoning attacks work by tricking a cache into storing a malicious response and serving it to other users. Mitigations include:

  • Validating and normalizing request inputs before they influence cache keys
  • Using Vary headers appropriately to segment caches
  • Avoiding caching responses that include unvalidated user input

Security Headers Should Not Be Cached Aggressively

Headers like Content-Security-Policy, X-Frame-Options, and Strict-Transport-Security should be consistent. If you're caching responses, make sure security headers are included in the cached response and aren't accidentally stripped by your caching layer.

Speaking of security headers — the Vulnerability Scanner can check whether your security headers are properly configured and identify common misconfigurations that caching might expose.


Debugging Cache Behavior

Caching bugs are infamously difficult to diagnose because the symptoms (stale content, unexpected responses) often look like application bugs. Here are practical debugging approaches:

Check Response Headers Directly

curl -I -H "Accept-Encoding: gzip" https://example.com/api/data

Look for:

  • Cache-Control — what directives are set
  • Age — how long the response has been in cache (CDN-added)
  • CF-Cache-Status — Cloudflare's cache status (HIT, MISS, EXPIRED, BYPASS)
  • X-Cache — similar header from other CDN providers

The Age Header

The Age header tells you how old a cached response is in seconds. If you're getting Age: 3540 on a response with max-age=3600, you know you're getting a cached response that's nearly expired.

Force Cache Bypass

Most CDNs support a cache bypass via request headers for debugging:

# Cloudflare cache bypass
curl -I -H "Cache-Control: no-cache" https://example.com/resource

Use Browser DevTools

The Network tab in browser DevTools shows cache status. Look for (from disk cache), (from memory cache), or 304 Not Modified responses. The Timing tab shows whether a request was served from cache (near-zero time) or hit the network.


Performance Impact: What Good Caching Actually Achieves

Proper caching configuration can have dramatic effects on both user experience and infrastructure costs. Some concrete numbers:

  • A cached response from a CDN edge node typically has latency of 1-10ms versus 50-500ms for an origin request
  • Bandwidth costs drop proportionally to your cache hit ratio — a 90% cache hit ratio means 90% less origin bandwidth
  • Compute costs (especially relevant for serverless/Workers) drop with cache hits since origin code never executes

The Website Performance Analyzer runs Lighthouse-based audits that include cache policy checks — it flags resources that are missing Cache-Control headers or have TTLs that are too short for static assets.

For SEO, caching also matters indirectly. Google's Core Web Vitals are heavily influenced by response times, and a well-cached site with fast TTFB (Time to First Byte) has a measurable advantage. The SEO Audit tool can help you identify performance issues that might be affecting your search rankings.


Putting It All Together: A Cache Header Strategy

Rather than copying headers from examples, think through your caching strategy systematically:

  1. Classify your responses — Is this public or private? Static or dynamic? How often does it change?

  2. Choose your TTL — Based on change frequency and acceptable staleness. Use stale-while-revalidate to soften the edges.

  3. Use content hashing for static assets — Enables immutable caching with instant cache busting via URL changes.

  4. Set appropriate Vary headers — Especially for content negotiation, but avoid Vary: User-Agent.

  5. Test with real tools — Don't assume your headers are correct. Verify with curl, browser DevTools, or dedicated inspection tools.

  6. Monitor cache hit rates — Most CDNs expose this in their dashboards. A hit rate below 70% usually indicates a configuration problem.

The arrival of Worker-level caches makes this discipline even more important. When your cache headers directly control whether your serverless code runs at all, the cost of getting them wrong — in both performance and money — is higher than ever.


Conclusion

HTTP caching headers are one of those foundational web technologies that reward deep understanding. They're not just performance hints — they're contracts between your server, intermediate caches, and browsers that affect security, cost, and user experience simultaneously.

With edge computing platforms adding increasingly sophisticated caching layers configured through these same standard headers, the investment in understanding them properly has never paid off more.

If you want to audit your current caching configuration, check for security header issues, or analyze your site's overall performance, OpDeck provides a suite of tools — including the Cache Inspector, Vulnerability Scanner, and Website Performance Analyzer — to help you identify and fix issues quickly, without setting up complex local tooling.