Engrain by ByteRush

WEB.13.01 Mid-level· 12 minCore — asked often

HTTP caching headers: Cache-Control, ETags and deploying without stale files

Read and write Cache-Control (max-age, s-maxage, no-cache vs no-store, private, immutable, stale-while-revalidate), validate with ETag and 304, understand heuristic freshness and Vary, and ship new JavaScript safely.

Comes up in: Web fundamentals, Recruiter screen, Frontend system design

Learn#

After every deploy, some of Pooja’s users see a blank page for a day. Their browsers kept yesterday’s index.html, which points to a JavaScript file the new deploy deleted.

Cache-Control tells every cache what it may do. A cached copy is fresh for max-age seconds. While fresh, it is used with no request. Freshness ends, then the cache must ask the server again. The safe deploy pattern is two rules:

# index.html: always check, cheap when unchanged
Cache-Control: no-cache
ETag: "v42"

# /assets/app.3f9a.js: the name changes when the content changes
Cache-Control: public, max-age=31536000, immutable

Validation asks “has it changed?” with the saved ETag (If-None-Match) or date (If-Modified-Since). If not, the server sends 304 Not Modified with no body.

HTML revalidates, hashed assets never askStep 1 of 4

Network

  • GET / → 200 (24 KB)
  • ETag: "v42"

Cache

  • / (stored, must revalidate)

The first visit downloads index.html with Cache-Control: no-cache and ETag: "v42".

Read the steps as text
  1. The first visit downloads index.html with Cache-Control: no-cache and ETag: "v42".
  2. The second visit: no-cache means "check first". The browser sends If-None-Match: "v42".
  3. Nothing changed, so the server answers 304 Not Modified with no body. The cached copy is used.
  4. The HTML links app.3f9a.js, cached with max-age=31536000, immutable. It is used with no request at all.

Predict#

Predict first

What does Cache-Control: no-cache mean?

Interview angle#

Say it like this — about 30 seconds

“No-store forbids caching. No-cache allows storing, but the copy must be checked before each use. An ETag names a version. The browser sends it back in If-None-Match, and the server answers 304 with no body if it still matches. To deploy safely, I give hashed files a long max-age, and the HTML no-cache. Then new HTML points to new files. Stale-while-revalidate serves a slightly old copy while it fetches a fresh one.”

Stays on your device. Nothing is uploaded.
Follow-up What is the difference between no-cache and no-store?
no-cache: store, but revalidate before use. no-store: do not store at all, for sensitive data.
Follow-up How do ETags work?
The server sends an ETag with the response; the client sends it back in If-None-Match; a match gets 304 Not Modified with no body.
Follow-up How do you deploy new JS without users getting stale files?
Content-hashed file names with a long max-age, and HTML with no-cache, so each deploy’s HTML references new names.

Practice#

Guided

Compute freshness lifetimes the way caches do, and answer conditional requests with 304 or 200.

Done when

  • s-maxage wins for shared caches; max-age beats Expires; heuristics apply only when nothing is set.
  • no-store, no-cache and private (for shared caches) give 0.
  • conditionalResponse handles lists, * and weak ETags.
Your solution
Ctrl/⌘ + Enter

Remember#

Try to answer each card before you open it. Then add them to your reviews.

no-cache vs no-store?

no-cache: store but revalidate before use. no-store: never store.

What does a 304 response mean?

Not Modified: use your cached copy; no body is sent.

What does s-maxage control?

Freshness in shared caches such as CDNs, overriding max-age there.

Which Cache-Control fits a content-hashed JS file?

public, max-age=31536000, immutable

What does stale-while-revalidate=60 allow?

Serving a stale copy for up to 60 s while refreshing in the background.

Go deeper

Four layers. Stop at the one your interview needs; each ends with a quick check.

The core ideaEvery round

public lets shared caches (CDNs) store it; private allows only the browser. s-maxage sets the lifetime for shared caches only. immutable says “never revalidate while fresh”: Firefox and Safari use it; Chrome ignores it.

Check yourself: Who may store a response marked private?

Only the browser's own cache, not CDNs or proxies.

How it works underneathSenior rounds

With no max-age or Expires, caches may guess. A common heuristic is 10% of the time since Last-Modified, so a file unchanged for 10 days may be cached for a day without asking Source: RFC 9111: Calculating heuristic freshness.
Always set explicit headers.

Check yourself: When does heuristic freshness apply?

When a cacheable response has no max-age or Expires; caches often use 10% of its age since Last-Modified.

Edge cases and trapsWhere people slip
Vary lists the request headers that change the response, such as Accept-Encoding, so caches store separate copies. Vary: Cookie or User-Agent splits the cache into thousands of copies, so hit rates collapse.
Check yourself: Why is Vary: Cookie dangerous at a CDN?

Every cookie value becomes its own cache entry, so the cache barely hits.

In productionStaff-level answers

stale-while-revalidate serves the old copy at once while refreshing; stale-if-error serves it when the origin fails. Both are great at the CDN for API data that can be a minute old Source: MDN: HTTP caching.

Check yourself: What does stale-if-error do?

Lets a cache serve a stale copy when the origin returns an error.

Finished the five steps? Mark it, and its cards join your reviews.

Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

Interview questions this answers

  • What is the difference between no-cache and no-store?
  • How do ETags work?
  • How do you deploy new JS without users getting stale files?
  • What does stale-while-revalidate do?