[Experimental] Implement option to opt out of revalidation after setting or deleting a cookie in a Server Action - #98058
Open
brunorodmoreira wants to merge 1 commit into
Conversation
…kie mutations in Server 操作
Setting or deleting a cookie in a Server Action marks the path as
revalidated, which re-renders the page into the action response and
invalidates the client router caches. For mutations that don't affect
rendered content (e.g. refreshing a session cookie), this is wasted work.
cookies().set() and cookies().delete() now accept an experimental
revalidate option; { revalidate: false } opts the mutation out:
- MutableRequestCookiesAdapter strips the option before it reaches the
underlying cookie store, skips the pathWasRevalidated marking, and
tracks whether any mutation requested revalidation (a monotonic latch
exposed via Symbol.for('next.mutated.cookies.revalidate')).
- addRevalidationHeader consults that latch instead of counting modified
cookies, so the x-action-revalidated header is not sent when all
mutations opted out. Opted-out cookies are still recorded as modified
and emitted via Set-Cookie, route handler responses, and redirects.
- Reworks vercel#84313 and addresses its review feedback: delete() support,
the action-handler cookie check, and the unused option extraction in
createCookiesWithMutableAccessCheck (the option is now handled by the
inner adapter proxy that userspace cookies forward into).
brunorodmoreira
marked this pull request as ready for review
August 28, 2026 21:26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
注册 for free
to join this conversation on GitHub.
Already have an account?
登录 to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reworks #84313 by @cramforce. That PR has been open since September 2025, now conflicts with canary after the recent action refactors, and hasn't had maintainer movement despite people asking for news on it through 2026 (better-auth among them). I opened this as a fresh PR so the feature can be tracked and reviewed against current canary. Happy to close this one if the original gets picked up instead.
What?
Adds an experimental
revalidate?: booleanoption tocookies().set()andcookies().delete(), on both call forms. Passing{ revalidate: false }opts that mutation out of marking the path as revalidated.When a mutation opts out, the action response skips the page re-render and the
x-action-revalidatedheader is not sent, so client router caches stay intact. The cookie still reaches the browser throughSet-Cookieas usual.Why?
Original report: https://x.com/madarco/status/1972314852036374833
better-auth/better-auth#9363 names the option from #84313 as the root fix for their session cookie workaround. Their idempotency check can't handle cookie values that carry a timestamp, so every refresh triggers a full re-render.
There is no workaround today. The re-render is embedded in the action response on the server, so it can't be avoided with a proxy or by stripping headers on the way out.
How?
All of the option handling lives in the inner
MutableRequestCookiesAdapter.wrapproxy. It stripsrevalidatebefore the option can reach the cookie store, setspathWasRevalidatedconditionally, and keeps a monotonic latch (Symbol.for('next.mutated.cookies.revalidate')) recording whether any mutation in the request asked for revalidation.addRevalidationHeaderinaction-handler.tsnow consults that latch instead ofgetModifiedCookieValues().length. This resolves madarco's review comment on the original PR: without it, the client is still told to revalidate.What's different from #84313:
delete()is supported in both call forms (madarco's other review comment).createCookiesWithMutableAccessCheckis resolved by forwarding the option untouched into the inner proxy.ActionRevalidationKindrefactor (Fix: Server refresh() should not purge client cache #86878). An opt-out never downgrades revalidation coming fromrefresh()orrevalidatePath().Opted-out cookies stay in the modified cookies list, so route handlers, redirects, and middleware
Set-Cookieemission are unchanged.Known limitation, documented in the JSDoc: cookies set in middleware and merged into the action always revalidate.