Implementing Caching

1. Setting Cache-Control Headers

DirectiveMeaning
publicAny cache may store
privateBrowser only — not shared caches
no-storeNever cache
no-cacheCache, but revalidate first
max-age=NFresh for N seconds
s-maxage=NSame, for shared caches
stale-while-revalidate=NServe stale while refreshing
immutableWill never change (long-lived assets)

Example: Public CDN cache

res.set("Cache-Control", "public, max-age=300, s-maxage=3600, stale-while-revalidate=86400");

2. Using ETag Headers

Example: ETag enabled by default

app.set("etag", "strong");  // or "weak" or false
// Express auto-generates ETag for res.send()/res.json() responses

3. Implementing Browser Caching

Example: Static assets

app.use("/assets", express.static("public/assets", {
  maxAge: "1y",
  immutable: true,
  etag: false
}));

4. Using apicache Package

Example: Install + use

import apicache from "apicache";
const cache = apicache.middleware;
app.get("/popular", cache("5 minutes"), getPopular);

5. Caching Specific Routes

Example: Per-route TTL

app.get("/news",     cache("1 minute"),  listNews);
app.get("/products", cache("10 minutes"), listProducts);

6. Setting Cache Duration

ResourceSuggested TTL
Hashed JS/CSS bundles1 year + immutable
Images30 days
HTML0–60 s
API list endpoints30–300 s
Per-user dataprivate, no-store

7. Invalidating Cache

Example: apicache clear

app.post("/products", async (req, res) => {
  await db.products.create(req.body);
  apicache.clear("/products");  // invalidate the list cache
  res.sendStatus(201);
});

8. Using Redis for Caching

Example: Cache-aside helper

import Redis from "ioredis";
const redis = new Redis(process.env.REDIS_URL);

export async function cached(key, ttlSec, fn) {
  const hit = await redis.get(key);
  if (hit) return JSON.parse(hit);
  const value = await fn();
  await redis.set(key, JSON.stringify(value), "EX", ttlSec);
  return value;
}

app.get("/products/:id", async (req, res) => {
  const data = await cached(`product:${req.params.id}`, 300, () => db.products.findById(req.params.id));
  res.json(data);
});

9. Implementing Cache-Aside Pattern

Read  : App ─▶ Cache (hit) ─▶ return
        App ─▶ Cache (miss) ─▶ DB ─▶ store in cache ─▶ return
Write : App ─▶ DB ─▶ delete cache key
        

10. Setting No-Cache Directives

Example: Sensitive endpoint

app.get("/me", requireAuth, (req, res) => {
  res.set({
    "Cache-Control": "no-store, no-cache, must-revalidate, private",
    "Pragma":        "no-cache",
    "Expires":       "0"
  });
  res.json(req.user);
});