Skip to the solution
HardFrontend6 min read

cacheLife and cacheTag — how do you configure TTL profiles?

249 views

The problem

Question presented to candidate: "With Cache Components on, how do you control how long a cached function lives and how do you invalidate it? Show me a custom profile."

What a strong answer should cover:

  • cacheLife(profile) inside a 'use cache' function or component sets three times: stale (client), revalidate (background refresh) and expire (hard limit).
  • Built-in profiles: default, seconds, minutes, hours, days, weeks, max; custom ones go in cacheLife in next.config.ts.
  • cacheTag('name') labels the entry; revalidateTag('name', 'max') or updateTag('name') invalidates it.
  • The build table shows each route revalidate and expire times, and responses get a matching s-maxage and stale-while-revalidate.
  • Short lifetimes are excluded from prerendering and must sit inside Suspense: revalidate of 0, expire under 5 minutes or stale under 30 s. Of the built-in profiles only seconds qualifies, because of its 1-minute expire.

Clarifying questions expected:

  • "How stale may this data be, and for whom?" — decides the profile; per-user data should not be cached this way at all.
  • "What event should refresh it?" — decides the tag.

Code / implementation expected: Yes — a built-in profile, a custom profile, and a tag with invalidation.

  • cacheLife
  • cacheTag

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

6 min read · 8 sections

Read the code

A custom profile, a tagged cached function, and invalidation
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
  cacheComponents: true,
  cacheLife: {
    catalogue: { stale: 300, revalidate: 3600, expire: 86400 },
  },
};
export default nextConfig;

// lib/catalogue.ts
import { cacheLife, cacheTag } from "next/cache";
export async function getProduct(id: string) {
  "use cache";
  cacheLife("catalogue");
  cacheTag("products", `product-${id}`);
  return db.product.findUnique({ where: { id } });
}

// app/admin/actions.ts
"use server";
import { updateTag } from "next/cache";
export async function saveProduct(id: string) {
  await db.product.update({ /* ... */ });
  updateTag(`product-${id}`); // read-your-own-writes for the editor
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 120 of 129 in Next.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Next.js questions
Up nextHard

unstable_cache vs `cache` (React) — which dedupes what?

Continue