InfoWok

CDNs and Object Storage: Cache Keys, Invalidation and Signed URLs (2026)

The production half of CDNs and object storage: which request parts belong in the cache key, when an origin shield pays off, what purging really costs, signed URLs and cookies, a cost model with worked numbers, and failing over to a second region.

NK
Navmeet Kaur
Published October 24, 2026
8 min read
Open in ChatGPT Open in Claude
CDN and object storage follow-ups: a viewer reaches an edge cache that talks to a shield, a primary bucket and a backup bucket in another region, beside the line keys, purges, signed URLsSoftware Architecture
CDN FOLLOW-UPS
On this page +

The CDN is in place and the first week goes well. Then the incidents start. A marketing link adds ?utm_source= to every URL and the hit ratio halves. A deploy purges everything and the origin falls over at nine in the morning. A paid video leaks because one URL never expired. The origin region has a bad hour and the site shows errors.

None of that changes the core idea, yet all of it decides whether the setup survives production. This lesson is the second half of CDNs and object storage, which covers what each part is and the hit-ratio arithmetic.

Intermediate35 min
Before you start
  • CDNs and object storage: the origin, the edge, hit ratio, TTLs and versioned file names.
  • Design a file storage service: presigned and multipart uploads, which this lesson only touches.
Remember from the core lesson

With a high hit ratio, why can users still complain about speed? The few misses take the slow path, so the p99 latency is the miss latency. The average hides the tail.

Key takeaways
  • Put a value in the cache key only if it changes the response. Every extra value multiplies the copies and cuts the hit ratio.
  • A shield merges misses from many edges, and it is billed, so use it when many edges ask for the same large file.
  • Version names instead of purging. A wildcard purge empties the cache and sends the full load to the origin.
  • Signed URLs fit one file and signed cookies fit many. Keep the bucket private behind the CDN.
  • Count the bill as storage plus requests plus egress, and see which layer pays the egress.
  • Failover between regions is only as fresh as the replication behind it.
After this lesson you can

Tune a CDN for production: choose the cache key, decide on a shield, plan a deploy without a purge storm, protect private files, estimate the monthly bill and design a regional failover, then answer the usual follow-ups in a line each.

What Belongs in the Cache Key?#

By default, CloudFront’s cache key is the domain and the URL path. Everything else is ignored until you add it, and every value you add splits the cache.

AWS gives a concrete case. A viewer’s Accept-Language header can arrive as en-US,en, en,en-US, en-US, en or en-US, all meaning English, so keying on it can store the same file up to four times. A better design puts the language in the URL (/en-US/story.html). User-Agent has thousands of variants, and session cookies can be unique per viewer, so AWS calls both poor candidates for the key.

If the origin needs a value only for logging or analytics, forward it with an origin request policy and keep it out of the key.

The reverse mistake

Leaving out a value that does change the response serves one person’s variant to everyone. That is the root of web cache poisoning: a request part the cache ignores, the unkeyed input. PortSwigger’s guidance is to cache only static responses and to disable request headers the site does not need. Per RFC 9111, a response with a Vary header may be reused only when the named request headers match.

When Does an Origin Shield Pay Off?#

Without a shield, 20 edges can each ask the origin for the same new file. An origin shield sends every edge miss through one place, so AWS says requests “are consolidated … resulting in as few as one request going to your origin”.

Assume 90 percent hits at the edge and 70 percent at the shield, as in the core lesson: that leaves ≈3 percent of traffic for the origin.

The cost side matters too. AWS bills the shield per request, and says it is a poor fit for dynamic, low-cacheability or rarely requested content. A GET with a TTL under 3,600 seconds counts as dynamic, so the shield is an extra billed hop on every such request.

Use a shield whenSkip it when
Viewers are spread across many regionsAlmost all viewers are near the origin
The origin is expensive per request (resizing, packaging)Files are small and the origin is cheap
Popular files are largeContent is mostly dynamic or short-lived

Also watch for request collapsing: several simultaneous misses for one file wait on a single origin fetch. Whether your CDN does this by default is worth checking, since it is what stops a popular file’s expiry from becoming a stampede.

What Does Invalidation Really Cost?#

Money first. CloudFront gives 1,000 invalidation paths free per month across the account, then bills per path. A path with a * wildcard counts as one path however many files it covers. Check the pricing page for the current rate. Assume a deploy changes 300 files and you purge each one, four deploys a month:

text
Per file: 300 × 4 = 1,200 paths
 free 1,000 → 200 billed
Wildcard /assets/*: 4 paths, free

The wildcard looks cheaper, but it has a hidden cost. Assume 50,000 hot files and 20 edge caches. After /*, every edge must refill, so the origin can see up to 50,000 × 20 ≈ 1,000,000 requests in a burst. Behind a shield it sees ≈50,000, one per file. Both numbers are assumptions that show the shape.

Time and reach matter as well. A purge is not instant, and it cannot reach copies already in browsers or office proxies, which is why AWS recommends versioned file names for anything updated often. Tag-based invalidation, where many objects share a tag and one call drops them all, exists on some CDNs, and CloudFront counts one tag as one path.

How Do Signed URLs and Cookies Protect Files?#

A private file needs two locks. The bucket must refuse direct requests, and the CDN must check each viewer. For the first, CloudFront origin access control signs the CDN’s requests so the bucket can stay private. For the second, AWS describes two tools:

ToolBest forTrade-off
Signed URLOne file, such as a downloadA new URL per file
Signed cookieMany files, such as every segment of a videoNeeds a client that keeps cookies

A signed URL is a bearer token: whoever holds it can use it until it expires, so sign for minutes, not days. Use signed cookies for a whole video, because signing each of hundreds of segments is wasteful. One trap: signed query parameters (Signature, Expires, Policy) must not be part of the cache key, or every viewer’s URL is a unique key and nothing is ever a hit. Confirm this in your CDN’s documentation.

Uploads are a different path

A presigned S3 URL goes straight to the bucket, valid for up to 7 days with SDK signing, and never touches the CDN. Chunking, resuming and multipart limits are in Design a file storage service, so this lesson does not repeat them.

What Does the Bill Look Like?#

Three meters run: storage, requests and egress. Egress is usually the big one, and it changes by layer. S3 does not charge for data sent to CloudFront, and Cloudflare R2 states that egress from R2 is free, with storage at $0.015 per GB-month and $0.36 per million Class B (read) operations. Prices change, so check the page on the day you decide.

A worked month, with every rate an assumption: deliver 100 TB (100,000 GB) of 400 KB files, which is 250 million requests, at a 95 percent hit ratio.

PathCalculationMonthly
Direct from origin100,000 GB × $0.09$9,000
Through a CDN100,000 GB × $0.05$5,000
Origin reads on misses12.5M × $0.0004 / 1,000$5

The $0.0004 per 1,000 GET figure is S3’s published rate for one region, and the two per-GB rates are assumptions. The saving of ≈$4,000 comes from the lower delivery rate, while the origin reads are tiny at a high hit ratio.

Per-request CDN fees are left out, so treat this as a shape, not a quote. On a zero-egress store, reading 250 million objects directly at $0.36 per million would be ≈$90. The best layer to pay for changes with the provider.

What If the Origin Region Fails?#

Failover in CloudFront uses origin groups, which try a primary origin and then a secondary on chosen status codes (any of 400, 403, 404, 416, 429, 500, 502, 503, 504), only for GET, HEAD and OPTIONS. By default it tries the primary for up to 30 seconds (3 attempts of 10 seconds). Cut the connection timeout to 2 seconds with one attempt and failover starts in about 2 seconds, an assumption to tune against flapping.

The secondary is a replica, only as fresh as the copy.

S3 Replication Time Control replicates 99.9 percent of objects within 15 minutes, so plan for new objects to be absent for that long. This is the consistency stance: the primary is strongly consistent, the replica is eventually consistent, and the edge may add TTL staleness on top.

Versioned, immutable names make failover safe. An old file is identical in both regions, and only a brand-new key can be missing. Do not fail over on 404 unless you want every genuine missing file to hit the secondary too.

Practice: Fix a 40 Percent Hit Ratio#

Exercise · Why is the hit ratio only 40 percent?15 min

A static site on a CDN shows a 40 percent hit ratio. The cache key includes all cookies, the User-Agent header and all query strings. Pages carry ?utm_campaign= tags. CSS and JS have the same name on every deploy, with max-age=60.

  1. List the changes that raise the ratio, in order.
  2. What should the CSS and JS headers be?
  3. After the fix, how do you ship a new app.js?
Hint

Ask of each key value: does it change the bytes? Then ask how often a file really changes.

One reasonable answer
text
1. Key = host + path only.
   Drop cookies and User-Agent.
   Allow-list the query strings
   that change output; ignore
   utm_*.
2. Hash the names: app.3f9a.js
   max-age=31536000, immutable
3. Build a new hash, update the
   HTML, deploy. No purge.

Only HTML needs a short TTL, so it points to new hashed assets. Forward the cookies the origin needs through an origin request policy, not the key. Measure origin request rate before and after, and watch for any page that really varies by cookie.

What Would You Watch in Production?#

Track five signals: edge hit ratio and the origin request rate, bytes served from the origin, origin 5xx rate, 4xx rate (a spike can mean a leaked or expired link) and purge counts. CloudFront logs mark shield hits as OriginShieldHit, so you can tell where a request stopped. Assume an SLO of 99.9 percent of requests under 300 ms, and tune it.

In an interview

Expect follow-ups. Answer each with a trade-off, not a product name:

They askAnswer in one line
Hit ratio dropped after a release?Check the key: new cookie, header or query string
Purge everything on deploy?No. Version names; a wildcard refill hits the origin
Do you need a shield?Many regions and a costly origin, yes
Paid video links leak?Private bucket, short signed cookies
One file, many users?Signed URL
Region down?Origin group; replica lags up to 15 minutes
Cost too high?Raise hit ratio, shrink objects, check which layer bills egress
Personal data?Skip the shared cache

Level expectations: a mid-level answer names the CDN and the hit ratio. A senior answer adds the key, versioned names, signed access and the failure path. A staff answer adds cost per layer, the replication lag in the failover and how the rollout is measured.

Check Yourself#

Check yourself4 questions · answer, then open
1.Why is the Accept-Language header a risky cache key value, and what is the safer design?

Equivalent values such as en-US,en and en,en-US are stored as separate copies, so the same file can be cached several times. Put the language in the URL path instead and keep the header out of the key.

2.A deploy purges /* and the origin slows down. What happened and how do you avoid it?

Every edge emptied at once and refilled from the origin. Version asset names so no purge is needed, and put a shield in front so the refill is one request per file.

3.Which do you use for a paid course with 400 video segments per lesson, and why?

A signed cookie, because it covers many files without changing URLs. Keep the bucket private behind origin access control and set a short expiry.

4.After failover, a photo uploaded two minutes ago returns 404. Why, and is it a bug?

Replication is asynchronous, so objects are copied within 15 minutes for 99.9 percent of them, so the new key may not exist in the secondary yet. It is expected, so design the client to retry or show a pending state.

In One Picture#

text
Key       only what changes bytes
Shield    many edges, dear origin
Change    new name, not a purge
Private   private bucket + signing
Bill      storage+requests+egress
Failover  replica lags; keep names
          immutable

Conclusion#

The core design is two boxes. The production answer is everything around them: a tight cache key, a shield only where it pays, file names that change instead of purges, private buckets with short-lived signing, a bill you can predict and a failover that admits its lag. Say which trade-off you took each time and the follow-ups get easy.

Which of these has caught your team out: the cache key, a purge, or a leaked link? Tell us in the comments.

Where to go from here

Frequently asked questions

What should go in a CDN cache key? +
Only the request parts that change the response. For static files that is usually the host and path. Adding cookies, a User-Agent header or tracking query strings makes the CDN store many identical copies and lowers the hit ratio.
Is it better to purge a CDN or version file names? +
For files that change often, version the name, so the new file is a new cache key and the old one is never touched. CloudFront's guide recommends this. Purging is for emergencies where a wrong file must disappear now.
When should you use signed cookies instead of signed URLs? +
Signed URLs suit one restricted file, such as a download. Signed cookies suit many restricted files at once, such as every segment of a video, and they leave the URLs unchanged.
Does an origin shield always save money? +
No. It adds a cache layer that is billed per request, and AWS says it is a poor fit for content with low cacheability or that is requested rarely. It pays off when many edges would otherwise ask the origin for the same file.

References

  1. Amazon CloudFront Developer Guide — Understand the cache key
  2. Amazon CloudFront Developer Guide — Use Origin Shield
  3. Amazon CloudFront Developer Guide — Pay for file invalidation
  4. Amazon CloudFront Developer Guide — Choose signed URLs or signed cookies
  5. Amazon CloudFront Developer Guide — Optimize high availability with origin failover
  6. Amazon S3 User Guide — Replication Time Control
  7. Amazon S3 User Guide — Download and upload objects with presigned URLs
  8. Amazon S3 pricing (GET request rate, free transfer to CloudFront)
  9. Cloudflare R2 documentation — Pricing
  10. RFC 9111: HTTP Caching (Vary and the secondary cache key)
  11. PortSwigger Web Security Academy — Web cache poisoning
Written by
Navmeet Kaur
Navmeet KaurSoftware Architecture & AI-Native Systems

Navmeet writes about software architecture for the AI era — how agentic systems are actually designed, not just demoed. Her work covers AI-native application architecture, agent orchestration and memory, context engineering, and where AI agents fit alongside (and eventually replace) traditional services and microservices. She focuses on the design decisions that survive production — state, tools, boundaries, and failure modes — turning fast-moving AI patterns into architecture developers can build on with confidence.

New AI engineering guides, the day they ship

Real Python, production depth. No digest spam.

Comments