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()androuter.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.