`router.push()` reuses cached redirect from prefetch without fresh middleware evaluation
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 142k
- Forks
- 32.5k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 351
Description
Link to the code that reproduces this issue
https://github.com/KumarNitin19/nextjs-prefetch-redirect-bug
To Reproduce
I'm running middleware that conditionally redirects based on a cookie value. The / route is protected and redirects to /process when the processingComplete cookie is not set.
Steps to Reproduce:
- Navigate to
/processpage (no cookie set) - Page renders with a sidebar containing
<Link href="/">Dashboard</Link> - Next.js automatically prefetches the
/route - Middleware evaluates and returns 307 redirect to
/process(because cookie is false) - Click "Start Process" button which:
- Performs async work (simulated 2 seconds)
- Sets cookie:
processingComplete=true - Calls
router.push('/')to navigate to dashboard
- Observe: User stuck on
/processpage, no navigation occurs
Live Demo (Vercel): https://nextjs-prefetch-redirect-bug.vercel.app/
Current vs. Expected behavior
Expected:
When router.push('/') is called after the cookie changes:
- Fresh GET request should be made to
/ - Middleware should re-evaluate with new cookie value
- Middleware should allow navigation (no redirect)
- User navigates to Dashboard
Current:
- No fresh request is made to
/ - Router reuses the cached redirect from initial prefetch
- Middleware is never re-evaluated
- User stuck on
/processpage
The router appears to cache the redirect response from the prefetch and reuses it on router.push() without checking if the state has changed.
Provide environment information
Relevant Packages:
- next: 15.5.8 (also tested on 15.5.9, bug reproduces on both)
- react: 19.1.0
- react-dom: 19.1.0
- typescript: ^5
Which area(s) are affected? (Select all that apply)
Linking and Navigating, Middleware
Which stage(s) are affected? (Select all that apply)
Vercel (Deployed), Other (Deployed), next build (local)
Additional context
Workarounds:
-
Disable prefetch (works reliably):
<Link href="/" prefetch={false}>Dashboard</Link> -
Hard navigation (works reliably):
window.location.href = '/'; -
Router refresh before push (unreliable):
router.refresh();
await new Promise(resolve => setTimeout(resolve, 100));
router.push('/');
Impact:
This affects any route where NextResponse.redirect() was previously returned by middleware. Once the redirect is cached from a prefetch, subsequent router.push() calls to that route will reuse the cached redirect without re-evaluating middleware logic, even if the application state has changed.
Common scenarios affected:
- Onboarding/signup flows with step-based redirects
- Authentication state transitions
- Feature flag-based routing
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked reproduction and trace the interaction between the Link prefetch, middleware redirect, and router.push('/'). Compare the cached redirect path with the expected fresh request after the processingComplete cookie changes; done means navigation reaches / and middleware re-evaluates instead of reusing the stale redirect.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, next.js, react
- Domain
- web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100