Deepen PracticeOrdered learning track

CloudFront Invalidation, Versioning, and Deployments

Learn AWS Networking and Content Delivery - Part 059

CloudFront invalidation, immutable versioning, cache-safe deployment, rollback, blue/green, canary, and operational release patterns for production-grade content delivery.

16 min read3168 words
PrevNext
Lesson 5972 lesson track40–59 Deepen Practice
#aws#cloudfront#cdn#content-delivery+3 more

Part 059 — CloudFront Invalidation, Versioning, and Deployments

In the previous parts, we treated CloudFront as a global edge proxy, cache, security boundary, and edge-compute platform. This part answers the production question that appears after the first successful distribution goes live:

How do we deploy new content safely when old content is already cached globally?

CloudFront deployment is not simply upload files to S3 and invalidate /*. That works in small systems, but it does not scale as a release discipline. In production, a CloudFront deployment is a coordination problem between:

  • object names,
  • cache keys,
  • cache TTL,
  • invalidation scope,
  • origin state,
  • browser cache,
  • DNS/front-door routing,
  • rollback strategy,
  • and release ownership.

A good deployment model makes cached content an ally. A bad deployment model turns the cache into a distributed stale-state machine.


1. Core Mental Model

CloudFront has many caches spread across edge locations and regional edge caches. A viewer request may be served from cache without touching your origin. That is the point.

The release problem is therefore:

new deployment exists at origin
but old deployment may still exist at edge
and old deployment may still exist in the browser
and some users may see old HTML with new JS
or new HTML with old JS
or old API schema with new frontend assumptions

Do not think of deployment as replacing bytes. Think of it as changing a graph of references.

For a web application, the graph often looks like this:

The HTML document is usually the mutable entrypoint. The JS/CSS/images are usually immutable assets. The API is usually dynamic and governed by compatibility rules.

That leads to the main invariant:

Mutable entrypoints may be invalidated. Immutable assets should be versioned.


2. Invalidation vs Versioning

AWS documents two primary ways to update content before cached objects naturally expire:

  1. invalidate cached files, so CloudFront fetches them again from origin on the next request;
  2. use versioned file names so the new content has a different URL.

These are not equivalent.

StrategyWhat ChangesBest ForWeakness
InvalidationSame URL, cache entry marked stale/removedHTML, metadata, emergency purgeOperationally asynchronous, can be overused, has path-count cost model
VersioningNew URL points to new objectJS, CSS, images, binaries, long-lived assetsRequires content-addressed build/references
Short TTLOld entry naturally expires soonSemi-dynamic contentHigher origin load and weaker cache hit ratio
No-store/no-cacheAvoid cache persistenceTruly user-specific or highly volatile contentGives up CDN benefit
Cache tag invalidationInvalidate by semantic tagsGroups of objects not aligned to pathsRequires deliberate tagging model

A mature system uses all of them, but not randomly.


3. Why invalidate /* Is a Smell

/* is useful during emergencies. It is a bad default release primitive.

It has several problems:

  • It destroys cache locality globally.
  • It causes the next wave of requests to refetch from origin.
  • It hides bad cache-key and TTL design.
  • It can amplify origin load after a deployment.
  • It makes every release behave like a cache outage.
  • It does not fix browser cache if browsers cached assets independently.
  • It can still race with clients that already loaded stale HTML.

Use global wildcard invalidation only when the business requirement is stronger than the cache-warmth requirement, such as security exposure, legal removal, severe content corruption, or broken release recovery.

A better default is:

invalidate mutable entrypoints only
use immutable file names for assets
keep API backward compatible
roll forward by changing references
roll back by repointing entrypoint references

4. Immutable Asset Versioning

Immutable asset versioning means the content hash is part of the file name.

Examples:

/assets/app.9f3a22c1.js
/assets/vendor.71be02ef.js
/assets/styles.510a7b8a.css
/assets/logo.2026-07-06.svg

If the content changes, the URL changes.

That gives you a powerful invariant:

A URL never changes meaning.

When this invariant holds, you can cache assets aggressively because /assets/app.9f3a22c1.js will always be the same bytes.

Recommended headers for immutable assets:

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

This does not mean every file should use one-year cache. It means files with content-addressed names can safely use long TTLs because a new deployment creates new URLs.

Bad Pattern

<script src="/assets/app.js"></script>
<link rel="stylesheet" href="/assets/style.css" />

This makes app.js mutable. If cached for long, users may keep old code. If cached for short, performance suffers. If invalidated on every release, origin load increases.

Better Pattern

<script src="/assets/app.9f3a22c1.js"></script>
<link rel="stylesheet" href="/assets/style.510a7b8a.css" />

The mutable object becomes only the HTML entrypoint that references the latest immutable assets.


5. The Entry Point Problem

The entrypoint is usually one of these:

/index.html
/app/index.html
/manifest.json
/service-worker.js
/config/runtime.json

Entrypoints are different from assets. They are pointers to a release.

A typical SPA release works like this:

The correct release order is important:

  1. Upload all immutable assets first.
  2. Verify assets exist at origin.
  3. Upload the new entrypoint last.
  4. Invalidate only the entrypoint paths.
  5. Run smoke tests through CloudFront, not only against origin.

Never publish an entrypoint that references assets not yet uploaded.


6. Cache-Control Contracts

Think of Cache-Control as a distributed consistency contract.

Common patterns:

ContentExampleCache-ControlDeployment Behavior
Immutable static asset/assets/app.hash.jspublic, max-age=31536000, immutableNever invalidate under normal release
HTML entrypoint/index.htmlpublic, max-age=60, stale-while-revalidate=... or controlled TTLInvalidate on release if quick rollout needed
Runtime config/config/runtime.jsonshort TTL, sometimes no-cacheCan change without rebuilding app
User-specific API/api/meprivate, no-storeUsually bypass CloudFront cache
Public API response/api/catalogexplicit TTL by business freshnessVersion API contract separately
Error response404, 500short error TTLAvoid caching transient origin failure too long

Important distinction:

  • Browser cache is controlled by response headers received by the browser.
  • CloudFront cache is controlled by CloudFront policies and origin headers.
  • Invalidation only affects CloudFront cache, not content already cached by browsers.

That is why immutable filenames are more reliable than relying purely on invalidation.


7. CloudFront Invalidation Semantics

Invalidation tells CloudFront to remove or mark cached objects as stale. On the next viewer request for that path, CloudFront goes back to origin.

Operational facts to internalize:

  • invalidation is not a synchronous global transaction;
  • wildcard invalidation can cover many objects;
  • invalidating a path invalidates all cached variants for that object across associated headers/cookies, but query string behavior needs care;
  • invalidation does not change origin content;
  • invalidation does not purge browser cache;
  • invalidation should be treated as a release event and logged.

Path Examples

/index.html
/manifest.json
/config/runtime.json
/assets/legacy-broken-file.js
/images/*
/*

A wildcard path can count as one invalidation path even if it affects many files, but using broad wildcards casually is still a performance and reliability smell.


8. Query Strings, Headers, Cookies, and Invalidations

Part 055 explained cache keys. Here is the deployment consequence.

If your cache key varies by query string, header, or cookie, CloudFront can hold multiple variants for the same logical path.

Examples:

/products?page=1
/products?page=2
/products?currency=USD
/products?currency=EUR

A deployment or purge policy must know whether the query string is part of the identity of the content.

Bad release thinking:

Invalidate /products and assume all variants are gone.

Better release thinking:

Do we cache /products by query string?
If yes, do we need /products* or exact paths?
Can we instead use cache tags or shorter TTL for this class?

Rule of thumb:

Every cache-key dimension creates a deployment invalidation dimension.

If you add Accept-Language, CloudFront-Viewer-Country, or Authorization to the cache key, you also expanded the number of cached variants that may need reasoning during release.


9. Cache Tag Invalidation

CloudFront supports invalidating cached objects by semantic tags. This is useful when your invalidation boundary does not map cleanly to URL paths.

Example use cases:

  • invalidate all pages related to product:1234;
  • invalidate all pages under tenant:alpha;
  • invalidate all fragments generated from catalog:v7;
  • invalidate all localized pages for a business entity.

Path-based invalidation is URL-structure dependent. Tag-based invalidation is domain-dependent.

Conceptually:

Design warning:

Cache tags are not an excuse to avoid TTL and cache-key design. They are a precision tool for domain-driven invalidation.

Use tags when you have a real entity/content graph. Do not tag everything with broad tags like all, site, or production and call it engineering.


10. Release Patterns for Static Websites

Pattern A — Small Static Site

Good for documentation, landing pages, internal tools.

- S3 origin
- CloudFront distribution
- long TTL for hashed assets
- short TTL or invalidation for HTML
- CI uploads assets first, HTML last

Release algorithm:

# 1. Build
npm ci
npm run build

# 2. Upload immutable assets with long cache
aws s3 sync dist/assets s3://my-site/assets \
  --cache-control "public,max-age=31536000,immutable"

# 3. Upload HTML/config with shorter cache
aws s3 cp dist/index.html s3://my-site/index.html \
  --cache-control "public,max-age=60"

# 4. Invalidate mutable entrypoint
aws cloudfront create-invalidation \
  --distribution-id E1234567890 \
  --paths "/index.html" "/manifest.json"

The important thing is not the exact command. The important thing is the order.

Pattern B — SPA With Runtime Config

Avoid baking environment-specific configuration into hashed JS when you need late binding.

/index.html                  short TTL
/config/runtime.json          short TTL
/assets/app.<hash>.js         long TTL immutable
/assets/chunk.<hash>.js       long TTL immutable

This lets you change API base URL, feature flags, or tenant metadata without rebuilding every asset.

But runtime.json becomes a mutable operational object. Treat it as configuration, not as random static content.

Pattern C — Documentation Site

Docs often need fast correction but also strong cache performance.

Recommended layout:

/docs/index.html              short TTL or invalidated
/docs/<slug>/index.html       moderate TTL
/assets/<hash>.js             long TTL immutable
/assets/<hash>.css            long TTL immutable
/search-index.<hash>.json     long TTL immutable
/latest-search-index.json     short TTL pointer if needed

Never make the entire docs site depend on invalidate /* unless your volume is tiny.


11. Release Patterns for Dynamic Origins

CloudFront is often in front of ALB, API Gateway, or a custom origin. The deployment problem is then less about S3 files and more about application compatibility.

Dynamic Origin Invariant

A new edge configuration must be compatible with both the old and new origin during rollout.

Examples:

  • If CloudFront starts forwarding a new header, old origin must tolerate it.
  • If CloudFront stops forwarding a cookie, origin must not depend on it.
  • If CloudFront rewrites URLs, both app versions should understand the path during transition.
  • If cache policy changes, you must reason about stale variants already cached.

Safe Dynamic Deployment Sequence

This mirrors database migration discipline:

expand -> migrate -> contract

For CloudFront:

make origin compatible -> update edge/cache behavior -> let old variants expire -> remove compatibility

12. Blue/Green With CloudFront

Blue/green is not one pattern. There are several layers where it can happen.

LayerBlue/Green MechanismUse When
DNSRoute 53 weighted/alias switch between distributionsYou need independent CloudFront distributions
CloudFront originSame distribution, switch origin or origin group behaviorYou want one stable hostname/distribution
Origin pathSame origin, change origin path from /blue to /greenStatic release trees in S3/custom origin
Application LBCloudFront points to ALB, ALB shifts target groupsApp team owns rollout behind stable CDN
Asset pointerHTML references new asset hashStatic asset rollout

Distribution-Level Blue/Green

Benefits:

  • strong isolation;
  • easy rollback by DNS weighting;
  • can test Green with its CloudFront domain or alternate staging domain;
  • safer for major distribution config changes.

Costs/trade-offs:

  • DNS TTL and resolver behavior matter;
  • certificate/CNAME ownership needs care;
  • duplicate distribution config can drift;
  • WAF/logging/security controls must be replicated.

Origin-Level Blue/Green

Benefits:

  • stable distribution and hostname;
  • less DNS movement;
  • easier to keep WAF/logging/common policies stable.

Risks:

  • distribution config updates are global control-plane operations;
  • rollback still requires CloudFront config deployment;
  • stale cache entries may survive unless URLs/cache keys differ.

13. Canary Releases

CloudFront can support canary-style rollout, but be precise about the layer.

Canary by DNS Weight

Use Route 53 weighted records pointing to separate CloudFront distributions.

Pros:

  • clear separation;
  • simple mental model;
  • rollback is DNS weight.

Cons:

  • DNS caching makes percentages approximate;
  • not ideal for per-request deterministic routing;
  • client stickiness is weak unless application handles it.

Canary by Edge Logic

Use CloudFront Functions or Lambda@Edge to route based on cookie/header/path.

Pros:

  • better request-level control;
  • can pin users to cohort;
  • does not require DNS change.

Cons:

  • code at edge becomes routing control plane;
  • must avoid cache poisoning by including cohort dimension when needed;
  • observability must distinguish cohorts.

Example request routing concept:

function handler(event) {
  var request = event.request;
  var headers = request.headers;

  if (headers.cookie && headers.cookie.value.includes('release=green')) {
    request.uri = '/green' + request.uri;
  } else {
    request.uri = '/blue' + request.uri;
  }

  return request;
}

Do not blindly copy this into production. The point is the invariant:

If release cohort changes response identity, the cache key or URI must reflect the cohort.

Otherwise, a green response can be cached and served to a blue user.


14. Rollback Design

A rollback must be designed before the release.

Static Site Rollback

With immutable assets, rollback is simple:

previous index.html -> references previous asset hashes
assets still exist -> rollback is republish previous entrypoint
invalidate /index.html

This is why you should not delete old hashed assets immediately.

Keep at least a retention window:

release artifacts retained for 30-90 days
or at least longer than max browser/cache TTL

Dynamic App Rollback

Rollback is harder because cached responses may encode behavior from the new version.

Questions to answer before release:

  • Are cached responses schema-compatible with the old app?
  • Did we change cache key dimensions?
  • Did we change forwarded headers/cookies/query strings?
  • Did we change authorization behavior?
  • Did we cache errors during the incident?
  • Which paths need invalidation on rollback?

Rollback checklist:

1. Stop traffic ramp or switch origin/DNS back.
2. Confirm origin old version is healthy.
3. Invalidate only incorrect mutable/dynamic paths.
4. Keep immutable assets from both versions available.
5. Watch 4xx/5xx/cache-hit/origin-latency metrics.
6. Compare CloudFront logs by release cohort or distribution.

15. Service Workers and Browser Cache

Service workers can break otherwise-correct CloudFront deployments.

A service worker is another cache layer with its own lifecycle. If it caches assets aggressively, CloudFront invalidation may not affect what the browser serves.

Recommended discipline:

  • version service worker explicitly;
  • avoid caching HTML entrypoints forever;
  • use content-hashed asset names;
  • test hard refresh and normal navigation;
  • test upgrade from N-1 and N-2 versions, not only fresh install;
  • provide a safe kill switch for bad service worker behavior.

For service workers, the release graph expands:

When debugging stale content, ask:

Is the response from browser memory/disk cache?
Is it from service worker?
Is it from CloudFront?
Is it from origin?

Do not assume the CDN is guilty.


16. API Deployment Behind CloudFront

For APIs, deployment safety depends on compatibility and cacheability.

Safe API Rules

  1. Do not cache user-specific responses unless the cache key includes the complete identity boundary, which is usually dangerous.
  2. Prefer additive API changes.
  3. Keep old fields and old semantics until cached clients naturally age out.
  4. Version breaking API changes in URL, header, or media type.
  5. Be careful caching 404 or 403; negative cache can hide newly-created resources.
  6. Use short error caching TTLs for volatile APIs.
  7. Include release version in logs and response headers for debugging.

Example response headers:

X-App-Version: 2026.07.06.1
X-Cache-Policy: public-catalog-v3
Cache-Control: public, max-age=60, stale-while-revalidate=300

These headers help correlate user reports with deployment state.


17. Cache-Safe CI/CD Pipeline

A mature CloudFront release pipeline has explicit phases.

Manifest Validation

Before upload, validate that every referenced asset exists in the build output.

Example release manifest:

{
  "release": "2026.07.06.1",
  "entrypoints": [
    "/index.html",
    "/manifest.json"
  ],
  "immutableAssets": [
    "/assets/app.9f3a22c1.js",
    "/assets/vendor.71be02ef.js",
    "/assets/style.510a7b8a.css"
  ],
  "invalidate": [
    "/index.html",
    "/manifest.json"
  ]
}

Deployment Gate

The pipeline should fail if:

  • an entrypoint references a missing asset;
  • an immutable asset is being overwritten with different bytes;
  • a mutable object is uploaded with one-year immutable caching;
  • invalidation paths are unexpectedly broad;
  • CloudFront smoke test still returns old release after a defined observation window;
  • canary cohort has elevated errors.

18. Safe S3 Upload Discipline

S3 sync is convenient but dangerous if not controlled.

Bad pattern:

aws s3 sync dist/ s3://site-bucket --delete
aws cloudfront create-invalidation --paths "/*"

Why it is risky:

  • --delete can remove assets still referenced by old HTML in browser/cache;
  • every release purges the CDN;
  • cache headers may be uniform and wrong;
  • rollback may fail because old assets were removed.

Better pattern:

# Upload hashed assets without deleting old hashes immediately
aws s3 sync dist/assets/ s3://site-bucket/assets/ \
  --cache-control "public,max-age=31536000,immutable" \
  --exclude "*" \
  --include "*.js" \
  --include "*.css" \
  --include "*.png" \
  --include "*.svg"

# Upload entrypoint separately
aws s3 cp dist/index.html s3://site-bucket/index.html \
  --cache-control "public,max-age=60,must-revalidate" \
  --content-type "text/html"

# Targeted invalidation
aws cloudfront create-invalidation \
  --distribution-id "$DISTRIBUTION_ID" \
  --paths "/index.html"

Garbage collection of old assets should be a separate job with retention logic, not part of every release.


19. Distribution Configuration Deployment

Changing CloudFront distribution config is different from changing content.

Examples of config changes:

  • add cache behavior;
  • change origin request policy;
  • change cache policy;
  • add CloudFront Function;
  • attach WAF web ACL;
  • add alternate domain name;
  • change TLS certificate;
  • enable Origin Shield;
  • change origin timeout.

These are control-plane changes. They take time to deploy globally and should be treated as infrastructure releases.

Recommended approach:

1. Store distribution config in IaC.
2. Use separate staging distribution for major config change.
3. Diff cache/origin policies before apply.
4. Apply during low-risk window if blast radius is high.
5. Monitor deployment status and distribution metrics.
6. Keep rollback config ready.

Do not mix risky CloudFront config changes with application release unless the dependency is explicit and tested.


20. Staging Distribution Pattern

A staging distribution is useful for validating CloudFront behavior before production.

Test in staging:

  • cache behavior selection;
  • header/cookie/query forwarding;
  • CORS;
  • signed URLs/cookies;
  • WAF interaction;
  • CloudFront Function/Lambda@Edge behavior;
  • origin TLS/SNI/Host header;
  • invalidation pipeline;
  • access log schema.

But remember: staging traffic volume and geographic distribution rarely match production. Staging proves correctness, not necessarily performance.


21. Deployment Failure Modes

SymptomLikely CauseHow to ProveFix
Some users see old UIHTML cached at edge/browser/service workerCheck Age, x-cache, browser cache, service workerTargeted invalidation, service worker update, shorter HTML TTL
New HTML references missing JSEntrypoint uploaded before assetsFetch asset URL via CloudFront and originUpload assets first, validate manifest
Users get mixed old/new chunksNon-hashed assets or deleted old assetsInspect HTML and network panelContent-hash assets, retain old assets
Invalidation did not affect variantQuery string path mismatchCheck cache key and invalidation pathUse wildcard/query-specific invalidation or better key design
Origin spike after releaseOverbroad invalidationCloudFront origin request metricsTarget invalidation, use versioning, warm critical paths
Rollback still brokenCached error/new variant remainsCheck logs by path/status/cache resultInvalidate affected paths, fix error TTL
Canary leaks to stable usersCache key lacks cohort dimensionCompare response headers/cookies and cache keyAdd cohort to URI/cache key or disable caching for canary response
CORS breaks after deployCached preflight or header policy mismatchInspect OPTIONS response and cache behaviorCache CORS correctly, invalidate preflight paths

22. Deployment Observability

Every release should emit enough data to answer:

Which release served this request?
Was it served from CloudFront cache?
Which cache behavior matched?
Which origin handled it?
Was this a canary user?
Was the object stale, refreshed, or newly fetched?

Useful headers:

X-Release-Id: 2026.07.06.1
X-Origin-Name: app-green
X-Cache-Policy-Name: static-assets-v4
X-Canary-Cohort: stable

Be careful not to expose sensitive internal data. Release IDs and non-sensitive policy names are usually acceptable; secrets and internal topology are not.

Log dimensions to preserve:

  • distribution ID;
  • cache behavior/path pattern;
  • origin identifier;
  • status code;
  • edge result type;
  • request ID;
  • user agent;
  • country/edge location;
  • release ID header from origin;
  • canary cohort if applicable.

23. Deployment Runbook

Normal Static Release

1. Build artifact.
2. Generate manifest of entrypoints and immutable assets.
3. Upload immutable assets with long TTL.
4. Upload mutable entrypoints with short TTL.
5. Invalidate entrypoints.
6. Smoke test through CloudFront hostname.
7. Verify x-cache behavior and release marker.
8. Watch 4xx/5xx/origin latency/cache hit ratio.
9. Keep previous assets for rollback window.

Emergency Purge

1. Identify exact sensitive/broken paths.
2. Prefer exact path invalidation.
3. Use wildcard only when path set cannot be enumerated safely.
4. Confirm origin contains corrected response or denies access.
5. Run CloudFront fetch from multiple regions if possible.
6. Confirm browser/service worker implications.
7. Record incident reason and invalidation paths.

Rollback

1. Restore previous entrypoint or switch origin/DNS back.
2. Invalidate mutable paths.
3. Do not delete new assets until investigation completes.
4. Monitor mixed-version symptoms.
5. Compare logs before/after rollback.

24. Engineering Checklist

Before using CloudFront for production deployments, ensure:

  • All static build assets are content-hashed.
  • Immutable assets are uploaded before mutable entrypoints.
  • Old assets are retained longer than max realistic cache/browser TTL.
  • HTML entrypoints have short TTL or release invalidation.
  • Runtime config is separated if late binding is required.
  • Invalidation paths are generated from release manifest.
  • /* invalidation requires explicit human approval or incident mode.
  • Cache keys are documented per behavior.
  • Canary cohort affects cache key or URI if response differs.
  • Rollback is tested through CloudFront.
  • Service worker upgrade path is tested.
  • Release ID appears in logs or safe headers.
  • Distribution config changes are IaC-managed and reviewed separately.

25. The Practical Rule

CloudFront deployment becomes simple when you stop mutating identity.

The strongest production pattern is:

immutable assets: new content -> new URL
mutable entrypoints: small set -> targeted invalidation
APIs: compatibility first -> cache carefully
edge config: IaC change -> tested and rolled out intentionally

That model avoids most CDN deployment incidents.


References

Lesson Recap

You just completed lesson 59 in deepen practice. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.