Skip to content

Libraries relying on monkey patching router.push no longer work with 15.3 #78085

Closed
@wintercounter

Description

@wintercounter

Link to the code that reproduces this issue

https://github.com/wintercounter/next-router-push-repro

To Reproduce

  1. Monkey-patch router.push
  2. 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
    )
  }

NEXT-4532

Metadata

Metadata

Assignees

No one assigned

    Labels

    Linking and NavigatingRelated to Next.js linking (e.g., <Link>) and navigation.linear: nextConfirmed issue that is tracked by the Next.js team.

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions