Question

Next.js App Router: reliable way to detect navigation start for a loading indicator

23a49165-9954-4a65-8794-1958f3e2ecac

Problem

In Next.js Pages Router you could do router.events.on('routeChangeStart', showSpinner). App Router removed router events entirely.

I need to show a global loading indicator the moment navigation begins — before the new page's server components finish fetching — and hide it when the route change completes.

What I've tried

1. usePathname + useSearchParams useEffect Works perfectly for detecting when navigation completes, but gives no signal for when it starts.

2. Monkey-patching window.history.pushState

const orig = window.history.pushState.bind(window.history)
window.history.pushState = (...args) => { showLoader(); return orig(...args) }

Unreliable — Next.js App Router appears to capture a reference to pushState at init time before the patch runs, so the override is never called.

3. Global click listener scoped to a + [role="link"]

document.addEventListener('click', (e) => {
  const anchor = e.target.closest('a')
  if (anchor && isInternalHref(anchor.href)) { showLoader(); return }
  if (e.target.closest('[role="link"]')) { showLoader() }
})

Catches the most common cases but misses:

  • Programmatic router.push() called from non-link UI (e.g. form submit → redirect, keyboard shortcuts)
  • router.replace() and router.prefetch() triggered navigation
  • Any link not using an anchor or role="link"

Question

Is there a complete, reliable way to hook into navigation start in Next.js 15 App Router? Looking for something that covers programmatic navigation, not just user click events.