Hi Vercel team,
We are seeing a reproducible issue on a Preview deployment involving Next.js Server Actions and stale Edge cache responses.
Project: gestao-doceria
Project ID: prj_duhqPB2z6ZUYWk7j6qaazeSwjIE4
Active Preview deployment: dpl_3TT8hzJso9Vxakq7ttd1NKmEtATc
The issue occurs on a Server Action POST to /login.
The response is consistently returned with:
x-vercel-cache: HIT
and also contains an x-nextjs-deployment-id from an older/unavailable deployment instead of the active immutable Preview deployment.
Example stale deployment ID observed: dpl_B4kmd7czzjbP83BjuGL7Srhq7ecE
We also observed other stale deployment IDs on previous runs.
The Server Action response includes:
x-action-redirect: /app;push
but before the browser reaches /app, the stale RSC/action payload references build-specific assets from the old deployment.
For example, one stale asset request was:
/_next/static/immutable/media/797e433ab948586e.p.1v5bejj26fx9h.woff2
which returns 404 on the active deployment.
The browser then ends up on the Next.js next_error screen.
Expected behavior: A Server Action POST using dynamic no-store headers should not be cached and should not be served across deployments.
Actual behavior: The POST response is served with x-vercel-cache: HIT and carries metadata from a different deployment.
Repository audit completed
We performed a full cache-header audit based on Vercel Support guidance.
next.config.ts:
- has a global /(.*) headers rule
- only adds security headers
- no Cache-Control
- no s-maxage
- no CDN-Cache-Control
- no Vercel-CDN-Cache-Control
src/middleware.ts:
- only adds x-request-id
- does not set any cache headers
There is:
- no vercel.json
- no proxy.ts
The only explicit application cache directives are:
Cache-Control: no-store
on GET-only health routes.
No repository rule matches or modifies:
- /login POST
- Server Action requests
- requests carrying Next-Action
The installed Next.js Server Action runtime explicitly emits:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
No project configuration overrides that header.
What we already tried
- Created a fresh replacement Preview deployment
- Confirmed the Preview environment points to the correct backend
- Successfully purged the Vercel CDN cache
- Re-ran the test after the purge
- Added a unique query string to /login on every run to avoid URL cache-key reuse
- Confirmed the issue still persists
- Verified /api/health/ready returns 200
- Verified the login page and referenced initial _next assets load successfully before submitting the Server Action
- Local Playwright E2E suites all pass
- Production was not involved in these tests
Even after CDN purge and unique login URLs, the Server Action POST still returned:
x-vercel-cache: HIT
with an x-nextjs-deployment-id belonging to a different deployment.
Vercel Support already confirmed in chat that:
“POST Server Action requests should not be cached or served across deployments with x-vercel-cache: HIT when dynamic no-store headers are set.”
They also stated that, after our repository audit, this behavior warrants investigation by the Support / Edge platform teams.
Questions
- Why is a POST Server Action response being served with x-vercel-cache: HIT?
- Why can an immutable Preview deployment hostname receive a Server Action/RSC response associated with another deployment?
- Which Edge cache layer is storing this response?
- Why did
vercel cache purge --type=cdn --yesnot invalidate it? - Is there another cache layer for Server Action / RSC payloads that is not affected by the normal CDN purge?
- Can someone from the Vercel Edge / Next.js platform team investigate this deployment?
I can provide Playwright traces, screenshots, request/response headers, and reproduction details if needed.
- Open the active immutable Preview deployment.
- Navigate to /login.
- Submit valid credentials using the Next.js Server Action.
- Inspect the POST /login request containing the Next-Action header.
- Observe:
- HTTP 303
- content-type: text/x-component
- x-action-redirect: /app;push
- x-vercel-cache: HIT
- x-nextjs-deployment-id pointing to an older deployment
- The client then requests stale build-specific _next assets.
- Those assets return 404 on the active deployment.
- The browser ends on the Next.js next_error page.