Closed
Description
Link to the code that reproduces this issue
https://github.com/wintercounter/next-router-push-repro
To Reproduce
- Monkey-patch
router.push
- Navigating using
Link
no longer calls it.
Current vs. Expected behavior
router.push
no longer called when using Link
since 15.3
Provide environment information
Operating System:
Platform: linux
Arch: x64
Version: #1 SMP PREEMPT_DYNAMIC Sat Feb 8 02:00:20 UTC 2025
Available memory (MB): 32023
Available CPU cores: 24
Binaries:
Node: 23.11.0
npm: 10.9.2
Yarn: N/A
pnpm: N/A
Relevant Packages:
next: 15.3.0 // Latest available version is detected (15.3.0).
eslint-config-next: 15.3.0
react: 19.1.0
react-dom: 19.1.0
typescript: 5.8.3
Next.js Config:
output: standalone
Which area(s) are affected? (Select all that apply)
Linking and Navigating
Which stage(s) are affected? (Select all that apply)
Other (Deployed)
Additional context
Many libraries are relying on monkey patching router.push
due to the (very) limited router support Next.js provides. Since 15.3
, Link
stopped using router.push
from context.
I understand monkey patching is an unsupported way of doing things, but there is simply no other way to handle specific cases, because Next doesn't provide any public APIs to give us control. I'd really like if it'd be considered
a. Using router.push
again for navigation.
b. Giving us APIs and Events for granular control over routing.
This was the previous code:
const navigate = () => {
// If the router is an NextRouter instance it will have `beforePopState`
const routerScroll = scroll ?? true
if ('beforePopState' in router) {
router[replace ? 'replace' : 'push'](href, as, {
shallow,
scroll: routerScroll,
})
} else {
router[replace ? 'replace' : 'push'](as || href, {
scroll: routerScroll,
})
}
}
This is currently with 15.3:
const navigate = () => {
if (onNavigate) {
let isDefaultPrevented = false
onNavigate({
preventDefault: () => {
isDefaultPrevented = true
},
})
if (isDefaultPrevented) {
return
}
}
dispatchNavigateAction(
as || href,
replace ? 'replace' : 'push',
scroll ?? true,
linkInstanceRef.current
)
}