Lesson 25 of 81
An editor hits publish on a CMS and wants to see the unpublished draft before it goes live — but your site is aggressively cached for everyone else. Draft Mode is the per-visitor escape hatch that shows one person the truth while everyone else keeps seeing the cache.
10 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
An editor enables Draft Mode via a CMS preview link and sees unpublished content. What do other visitors browsing the same site at the same time see?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
draftMode(), imported from next/headers, is an async function that lets you enable or disable Draft Mode for a request, and check whether it's currently on. When Draft Mode is enabled for a given browser, that browser's requests bypass caching almost entirely: fetch() calls skip the fetch cache and hit the network directly, 'use cache'-marked functions and components re-execute instead of returning a cached result, unstable_cache is bypassed the same way, and the page is excluded from the ISR response cache. Everyone else still gets the normal cached, pre-rendered version — Draft Mode is scoped to the one visitor carrying the bypass cookie, not a global switch.
The mechanism is a cookie: calling enable() sets __prerender_bypass, a value regenerated on every next build so it can't be guessed. Whoever's browser carries that cookie sees fresh, uncached content on every request; everyone without it keeps hitting the cache as normal.
// app/api/draft/route.ts
import { draftMode } from "next/headers";
import { redirect } from "next/navigation";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const secret = searchParams.get("secret");
const slug = searchParams.get("slug");
if (secret !== process.env.CMS_PREVIEW_SECRET || !slug) {
return new Response("Invalid token", { status: 401 });
}
const draft = await draftMode();
draft.enable();
redirect(slug);
}
A headless CMS's "Preview" button opens a URL like /api/draft?secret=XXX&slug=/posts/foo in a new tab. This Route Handler checks the shared secret so only the CMS (not any random visitor) can flip the switch, calls draft.enable() to set the bypass cookie, then redirects to the actual page — which fetches fresh, unpublished content because the cache is now bypassed for this one browser. No branching logic is needed in the page itself if the CMS serves draft and published content from the same URL; the cache bypass alone is what changes.
enable() and disable() can only be called from a Route Handler or a Server Action — never from inside a 'use cache' scope. Calling either one inside a cache directive throws. This is a real constraint, not a style suggestion: the toggle has to happen at a request boundary, not inside the cached function itself.isEnabled is allowed inside a 'use cache' scope, even though toggling isn't. A cached component can check whether Draft Mode is on and render a preview banner — the cache bypass still applies, so it re-executes with fresh data on every draft request even though the read itself is permitted where the write isn't.next build, so a stale deployed build's cookie value won't work against a freshly built one — this is deliberate, so the cookie value can't be guessed or reused indefinitely.draftMode() is async and must be awaited, same as cookies() and headers() — treating it as synchronous is a leftover habit from Next.js 14 and earlier, where it briefly still worked but is on its way out."An editor says they published a change in the CMS but the live site still shows the old content, yet the preview button shows the new content correctly — what's going on?" tests whether a candidate understands that caching and Draft Mode are two different, deliberately separate systems: the live site is correctly serving cache until revalidation, and the preview link works precisely because Draft Mode bypasses that same cache for one visitor.