How to programmatically change a route in Next.js
By Flavio Copes
Learn how to programmatically change a route in Next.js 16 with useRouter from next/navigation, plus the older Pages Router alternative.
To programmatically change a route in Next.js 16 you call router.push(), passing the URL you want to navigate to. It performs a client-side navigation, the same kind you get when clicking a Link component.
In an App Router Client Component, you get the router with useRouter from next/navigation:
'use client'
import { useRouter } from 'next/navigation'
//...
const router = useRouter()
router.push('/dashboard')
This is what you use when the navigation is a consequence of some logic, not a click on a link. After a form submission, after a successful login, after a countdown ends.
How do you pass query parameters?
Build the path string, including the query:
router.push('/products?category=books')
Or compose it from variables:
const category = 'books'
router.push(`/products?category=${encodeURIComponent(category)}`)
push() or replace()?
router.push() adds an entry to the browser history. The user can press back and return to the previous page.
Sometimes that’s wrong. After a login, pressing back should not show the login form again. Use router.replace() in those cases:
router.replace('/dashboard')
Same navigation, but the current history entry gets replaced instead of a new one being added.
Be careful with redirects during render
A common mistake is calling router.push() directly in the component body, to send away users who shouldn’t see a page. That code runs while React is rendering, and Client Components are pre-rendered on the server too, where there’s no browser to navigate.
Put the call inside useEffect instead, so it runs in the browser after the component mounts:
'use client'
import { useEffect } from 'react'
import { useRouter } from 'next/navigation'
export default function Dashboard({ user }) {
const router = useRouter()
useEffect(() => {
if (!user) {
router.push('/login')
}
}, [user, router])
// ...
}
The component renders once, the effect runs, and the user gets redirected.
If you know on the server that the user has to go somewhere else, don’t wait for the client at all. Call redirect() from next/navigation inside the Server Component or Server Action, and the browser never renders the protected page.
Outside a Client Component?
useRouter is a React hook. It only works in Client Components.
On the server, use redirect() or permanentRedirect() from next/navigation. In a shared client-side utility function, where hooks don’t work, pass the router in as an argument from the component that called useRouter(). The App Router has no global router object to import.
Pages Router (older apps)
Apps that still use pages/ import from next/router:
import { useRouter } from 'next/router'
const router = useRouter()
router.push('/dashboard')
Outside a component, the Pages Router also exposes a default export:
import Router from 'next/router'
Router.push('/dashboard')
That global Router import is a Pages Router pattern. New App Router code should not rely on it. Declarative links are still covered in linking two pages in Next.js.
Want me to talk about your product? You can sponsor this site.
Related posts about next: