Stop 11 · CachingTopics · 8/8

HTTP Caching Headers

Part of the Backend Developer Roadmap

In short

Before you set up any Redis, the browser itself can cache for you, for free. A few response headers decide whether it reuses a file, checks back first, or downloads it again.

Response headers (`Cache-Control`, `ETag`, `Last-Modified`) that tell browsers and CDNs how and whether to cache a response, without needing any custom caching infrastructure.

The blob character checks a milk packet's tag at the fridge while holding a small hourglass.

Think of it like this

The date on the milk packet

A milk packet says 'best before'. Before that date, you just use it. After, you check it's still fine before pouring. Cache-Control is that best-before date. An ETag is how the browser asks 'still the same milk?' and gets a quick yes instead of a new packet.

Watch it happen

Fresh, revalidated, then changed

Browser
Server

GET /api/menu

1/7First visit. The browser has nothing cached.

The big ideas

What you need to know

Cache-Control sets freshness

max-age=60: reuse for 60 seconds. no-cache: always check first. no-store: never keep a copy.

ETag is a fingerprint

The server tags each version. The browser sends it back in If-None-Match to ask whether it changed.

304 saves bandwidth

If nothing changed, the server replies 304 with no body, and the browser uses its saved copy.

public vs private

public lets CDNs cache it too. private means only the user's own browser may keep it.

See it in code

Walk through the code

ts
1import crypto from "node:crypto";2 3app.get("/api/menu", async (req, res) => {4  const menu = await db.menu.today();5  const body = JSON.stringify(menu);6  const etag = `"${crypto.createHash("sha1").update(body).digest("hex")}"`;7 8  res.set("Cache-Control", "public, max-age=60");9  res.set("ETag", etag);10 11  if (req.headers["if-none-match"] === etag) return res.status(304).end();12  res.type("json").send(body);13});

1/4Build the response and fingerprint it. An ETag value is a quoted string.

Express already adds weak ETags to res.send responses and answers 304s for you. This shows what happens under the hood.

Save yourself the pain

Common mistakes

Oops

Thinking no-cache means 'don't cache'.

Do this instead

no-cache means 'store it, but check with the server before every reuse'. To forbid storing, use no-store.

Oops

Setting a long max-age on HTML that changes often.

Do this instead

Users won't see updates until it expires. Keep HTML short-lived or revalidated; give long max-age to fingerprinted assets.

Your mission

See a 304 with your own eyes

~20 min

Quick check

A response has Cache-Control: no-cache. What does the browser do?

Go deeper

  1. 1Set appropriate `Cache-Control` headers on a few different types of endpoints.
  2. 2Implement `ETag` support so clients can avoid re-downloading unchanged data.
  3. 3Learn the difference between `no-cache` (revalidate) and `no-store` (never cache).

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge