-
Notifications
You must be signed in to change notification settings - Fork 30.2k
Description
Link to the code that reproduces this issue
https://github.com/angeloashmore/cache-components-draft-mode-dynamic-apis
To Reproduce
- Visit http://localhost:3000/ — page renders without
cookies() - Visit http://localhost:3000/api/draft — enables Draft Mode
- Visit http://localhost:3000/ — page renders with
cookies()and throws
Current vs. Expected behavior
Current behavior:
When Draft Mode is enabled and I try to call cookies() inside a "use cache" function, Next.js throws an error:
Error: Route / used `cookies()` inside "use cache". Accessing Dynamic data
sources inside a cache scope is not supported. If you need this data inside a
cached function use `cookies()` outside of the cached function and pass the
required dynamic data in as an argument. See more info here:
https://nextjs.org/docs/messages/next-request-in-use-cache
This error occurs even though Draft Mode is enabled, which means the cache is already being bypassed (as fixed in #76581 / PR #77141).
Expected behavior:
When Draft Mode is enabled, dynamic APIs like cookies() and headers() should be allowed inside "use cache" functions, since:
- The cache is already bypassed — PR Bypass
"use cache"caches when Draft Mode is enabled #77141 correctly skips cache reads and writes when Draft Mode is enabled - Draft Mode inherently requires dynamic behavior — The whole point of Draft Mode is to render fresh, request-specific content
- This was the previous behavior — With the fetch cache, Draft Mode allowed reading cookies to pass preview tokens to CMS APIs
draftMode().isEnabledis already allowed — As noted in PR fix(after): allow reading draftMode status in after #73324,draftMode().isEnabledis permitted inside"use cache"because "when it's on, it switches everything to dynamic rendering anyway, so that prerender/cache entry is ignored." The same logic should apply to other dynamic APIs.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.1.0: Mon Oct 20 19:32:41 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T6000
Available memory (MB): 32768
Available CPU cores: 10
Binaries:
Node: 24.5.0
npm: 11.5.1
Yarn: 4.7.0
pnpm: 10.8.0
Relevant Packages:
next: 16.1.1-canary.5 // Latest available version is detected (16.1.1-canary.5).
eslint-config-next: N/A
react: 19.2.3
react-dom: 19.2.3
typescript: 5.9.3
Next.js Config:
output: N/AWhich area(s) are affected? (Select all that apply)
Cookies, Draft Mode, cacheComponents, Headers
Which stage(s) are affected? (Select all that apply)
next dev (local), Vercel (Deployed), Other (Deployed), next start (local)
Additional context
This is a common pattern when integrating with headless CMS platforms (Prismic, Contentful, Sanity, Storyblok, etc.):
- Editor clicks "Preview" in the CMS → CMS redirects to
/api/draft?token=xyz - API route enables Draft Mode and stores the preview token in a cookie
- Page renders with Draft Mode enabled → needs to read the preview token cookie to authenticate with the CMS preview API
With full-page caching via "use cache", this pattern is broken because we cannot read the preview token cookie, even though Draft Mode has already bypassed the cache.
Proposed Solution:
When Draft Mode is enabled, the "use cache" boundary should behave as if it doesn't exist — allowing dynamic APIs (cookies(), headers(), searchParams, etc.) without throwing an error.
This is consistent with the existing behavior where:
- Cache reads are skipped when Draft Mode is enabled
- Cache writes are skipped when Draft Mode is enabled
draftMode().isEnabledis allowed inside"use cache"
Related issues and PRs:
- "use cache" directive is not bypassed when draftMode is enabled #76581 —
"use cache"directive is not bypassed when draftMode is enabled (fixed) - PR Bypass
"use cache"caches when Draft Mode is enabled #77141 — Bypass"use cache"caches when Draft Mode is enabled - PR fix(after): allow reading draftMode status in after #73324 — Allow reading
draftModestatus (established thatdraftMode().isEnabledis not a "real" dynamic API in cache contexts) - Docs: How to intentionally block in Cache Components? #86739 — Docs: How to intentionally block in Cache Components? (discusses the
<Suspense fallback={null}>workaround pattern) - brunorzn/nextjs-draftmode-devmode-example#1 —
SuspendedDraftModewrapper pattern (does not solve this issue)