`next/router`
to `next/navigation`
migration cheatsheet
Sep 6, 2024 • 3 min read
Wrote down the sheet I wish I had.
Image by black-forest-labs/flux-dev Last updated: Mar 12, 2025
You might find this useful when migrating a Next.js app from the Pages Router to the App Router.
Properties of the next/router
object and their equivalent using next/navigation
exports.
import { useRouter } from 'next/router'
const { pathname , query , asPath } = useRouter ()
import { usePathname } from 'next/navigation'
const pathname = usePathname ()
import { useSearchParams } from 'next/navigation'
const searchParams = useSearchParams ()
const query = Object . fromEntries ( searchParams ?? new URLSearchParams ())
Note how Object.fromEntries
handles search params with multiple values:
Object . fromEntries ( new URLSearchParams ( { status : [ "foo" , "bar" ] } ))
// output: { status: 'foo,bar' }
If instead you need the shape { status: ['foo', 'bar'] }
unfortunately you will need to manually assemble the object.
Also, note how arrays are serialized to strings:
new URLSearchParams ( { status : [ "foo" , "bar" ] } ) . toString ()
// output: `status=foo%2Cbar`
const sp = new URLSearchParams ()
sp . append ( "status" , "foo" )
sp . append ( "status" , "bar" )
sp . toString ()
// output: `status=foo&status=bar`
If you also consumed dynamic params via the query object in the Pages Router, you can merge the object returned by useParams
:
import { useSearchParams , useParams } from 'next/navigation'
const searchParams = useSearchParams ()
const params = useParams ()
const searchParamsRecord = Object . fromEntries ( searchParams ?? new URLSearchParams ())
const query = { ... searchParamsRecord , ... params }
It's important to note that the App Router will not handle omitting dynamic params if you used to spread existing params while linking or navigating.
import { Link } from 'next/link'
// In the Pages Router, dynamic params will be omitted automatically.
// In the App Router, you have to handle this manually.
< Link href = {{
query : { ... query , foo : "bar" }
}} />
// This also applies when navigating using router methods e.g. router.push
import { usePathname , useSearchParams } from 'next/navigation'
const pathname = usePathname ()
const searchParams = useSearchParams ()
const asPath = pathname + "?" + searchParams
import { useRouter } from 'next/router'
const { pathname , query , replace } = useRouter ()
replace ( { pathname , query : { ... query , foo : "bar" } } )
import { useRouter , useSearchParams , usePathname } from 'next/navigation'
const { replace } = useRouter ()
const readOnlyParams = useSearchParams ()
const pathname = usePathname ()
const searchParams = new URLSearchParams ( readOnlyParams ?? {} )
searchParams . set ( "foo" , "bar" )
replace ( pathname + "?" + searchParams )
This is documented by Next.js . Unfortunately, there isn't a direct migration path for every use case and you might have to make drastic changes.