ref
<aside> đź’ˇ For this doc, leave your feedback as a comment on this public document.
To report an issue with codemods, use the reporting feature inside VS Code extension, or just open an issue in the Codemod Registry.
</aside>
Explaination of Step IDs V = Versioning N = Navigation B = Bootstrapping C = Server & Client Components A = API Routes
Step ID | Step Name | Codemod name | Codemod deep-link | Auto Cov. | Description of Changes |
---|---|---|---|---|---|
V1 | Bump React and React DOM to the newest version | - | - | Now: 0% | |
N/A | |||||
V2 | Bump Next.js version to v13.4 in the project | - | - | Now: 0% | |
Find all package.json files and bump the next property to ^13.4.0 . After that, run your package manager to update your respective node_modules files |
|||||
N1 | Replace router.query usages with useSearchParams |
Replace Next Router | vscode://intuita.intuita-vscode-extension/showCodemod?chd=-wqkAQr7ILgYeTRozWTEgiUvmSY |
Now: 80% |
| The router prototype coming from the return value of useRouter
from next/navigation
does no longer have the query
attribute. You can replace this functionality by using the return value of useSearchParams
from next/navigation
. We will call this value searchParams
from this moment on.
The searchParams
might be nullable if it is used within the pages
directory. Otherwise, they will be a read-only URLSearchParams
map, not a plain old JavaScript object like query
.
You can use the nullability of the searchParams
to check if the routing is already available to use in your component.
The searchParams
might contain multiple results under one key. To get values for key a
, write either searchParams?.getAll('a')
or searchParams?.get('a')
. It is safer to use getAll
.
You cannot delete values from searchParams
. The similar behavior would be to use the push
or replace
functionality of Next.js’ router. |
| N2 | Replace router.asPath
with usePathname
| Replace Next Router | vscode://intuita.intuita-vscode-extension/showCodemod?chd=-wqkAQr7ILgYeTRozWTEgiUvmSY
| Now: 80%
| The router
prototype coming from the return value of useRouter
from next/navigation
does not contain the asPath
attribute. You can use the return value of the usePathname
hook from next/navigation
. We will call this return value the pathname
from this moment on.
The pathname
might be nullable if it is used within the pages
directory. Otherwise, they will be a string
.
You can use the nullability of the pathname
to check if the routing is already available to use in your component. |
| N3 | Replace router.pathname
with usePathname
| Replace Next Router | vscode://intuita.intuita-vscode-extension/showCodemod?chd=-wqkAQr7ILgYeTRozWTEgiUvmSY
| Now: 80%
| The router
prototype coming from the return value of useRouter
from next/navigation
does not contain the pathname
attribute. You can use the return value of the usePathname
hook from next/navigation
. |
| N4 | Remove the router.isFallback
usages | Replace Next Router | vscode://intuita.intuita-vscode-extension/showCodemod?chd=-wqkAQr7ILgYeTRozWTEgiUvmSY
| Now: 80%
| The router
prototype coming from the return value of useRouter
from next/navigation
does not contain the isFallback
attribute.
The fallback functionality is no longer supported.
Since you might have boolean expressions that depend on router.isFallback
, you might want to remove the branches that depend on router.isFallback
being true. |
| N5 | Replace router.isReady
with true | Replace Next Router | vscode://intuita.intuita-vscode-extension/showCodemod?chd=-wqkAQr7ILgYeTRozWTEgiUvmSY
| Now: 80%
| The router
prototype coming from the return value of useRouter
from next/navigation
does not contain the isFallback
attribute.
You can either replace router.isReady
with true
(and subsequently remove branches executed when router.isReady
was true
) or use a nullability check over useSearchParams
, usePathname
or useParams
return values. |
| N6 | Reduce number of router.push
and router.replace
arguments to 1 | Replace Next Router | vscode://intuita.intuita-vscode-extension/showCodemod?chd=-wqkAQr7ILgYeTRozWTEgiUvmSY
| Now: 80%
| The router prototype coming from the return value of useRouter
from next/navigation
contains a simplifying version of the push
method.
The first and only argument in the new API is the string
href. You can get it by transforming the first argument into string (which might require conversion from an URLObject
).
The second parameter of the old API is not supported. If you use it, you need to readjust the href
parameter in the new API accordingly.
The third parameter of the old API is not supported. Automated scrolling should be achieved by writing the scrolling code yourself. Shallow routing is not supported. Locale needs to be handled by your custom code. |
| N7 | Remove router.basePath
usages and implement this feature in a different way | - | - | Now: 0%
| The router
prototype coming from the return value of useRouter
from next/navigation
does not contain the basePath
attribute.
You can replace usages of router.basePath
with a constant string you likely have put into the basePath
attribute of the default-exported object in next.config.js
|
| N8 | Remove router.locale
, router.locales
, router.defaultLocale
, and router.domainLocales
and implement internationalization in a different way | - | - | Now: 0%
| The router
prototype coming from the return value of useRouter
from next/navigation
does not contain the locale
, locales
, defaultLocale
and domainLocales
attributes.
Locales are no longer supported directly in the App Router of Next.js. Pick your own solution or follow the guide here: https://nextjs.org/docs/pages/building-your-application/routing/internationalization |
| N9 | Remove router.events
| - | - | Now: 0%
| The router
prototype coming from the return value of useRouter
from next/navigation
does not contain the events
attribute.
The router events are not directly supported. You can react on pathname
and searchParams
changes as outlined here: https://nextjs.org/docs/app/api-reference/functions/use-router#router-events |
| N10 | Replace useRouter
from next/router
to useRouter
from next/navigation
| Replace Next Router | vscode://intuita.intuita-vscode-extension/showCodemod?chd=-wqkAQr7ILgYeTRozWTEgiUvmSY
| Now: 100%
| Once all to-be-removed properties of router
have been handled, we can switch to use the router
object as returned from useRouter
from next/navigation
|
| B1 | Create the root layout | App Directory Boilerplate | vscode://intuita.intuita-vscode-extension/showCodemod?chd=QKEdp-pofR9UnglrKAGDm1Oj6W0
| Now: 50%
| Create a component that renders the rudimentary top-level HTML in app/layout.tsx
(html and body tags are mandatory).
https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration#step-2-creating-a-root-layout |
| B1.1 | Update dynamic imports | App Directory Boilerplate | | Now: 0%
Soon: 0% | Module resolution changes can affect
dynamic imports in API Routes.
https://www.notion.so/intuita/Module-Resolution-in-API-Routes-9325e55ab3314e9c8d1801b8f37ac6e1 |
| B1.2 | Update _app providers | App Directory Boilerplate | | Now: 0%
Soon: 0% | Some libraries previously used in _app (e.g next-i18next) dont support next 13 app router.
Such libraries should be replaced or forked and fixed. |
| B2 | Add global styles to the root layout file | App Directory Boilerplate | vscode://intuita.intuita-vscode-extension/showCodemod?chd=QKEdp-pofR9UnglrKAGDm1Oj6W0
| Now: 100%
| Put global styles imports in app/layout.tsx
|
| B3 | Migrate the styles | Move CSS in JS Styles | vscode://intuita.intuita-vscode-extension/showCodemod?chd=fPpa1xqB9D0AN4VazhrRkrWri9g
| Now: ~20%
Soon: TBD | Some CSS libraries might not be supported by Next.js. You need to check your CSS architecture and pick a proper solution. see the CSS in JS doc here. |
| B4 | Add metadata to the root layout file | Replace Next Head | vscode://intuita.intuita-vscode-extension/showCodemod?chd=HCouE4WzwvH-jcfOJ3xYLz4YaTA
| Now: 80%
Soon: 100% | Next/Head meta tags should be moved to the metadata object or generateMetadata
function.
https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration#step-3-migrating-nexthead |
| B5 | Create the root app/page.tsx
| App Directory Boilerplate | vscode://intuita.intuita-vscode-extension/showCodemod?chd=QKEdp-pofR9UnglrKAGDm1Oj6W0
| Now: 80%
| Migrate the server components of pages/_app.tsx
and pages/_document.tsx
to app/page.tsx
The client components should be either part of the root “client component” file or the “root layout”.
Breaking changes:
__NEXT_DATA__
equivalent passed to the layout componentgetInitialProps
pageProps
and Component
passed to the default /pages/_app.tsx
componentvscode://intuita.intuita-vscode-extension/showCodemod?chd=QKEdp-pofR9UnglrKAGDm1Oj6W0
| Now: 0%
Soon: 100% | N/A. |
| B7 | Move client code such as React Context, React Hooks, to the client component(s) files | - | - | Now: 0%
| We cannot use React contexts or hooks within server components. |
| B8 | Create the middlewares | - | - | Now: 0%
| Identify if your project uses i18n and choose an architecture for i18n to move to; consider using middlewares for that.
Identify which other middlewares should be integrated with the App router. |
| B9 | Migrate the redirects to the configuration or some middleware | - | - | Now: 0%
| Redirects done in the root page have to be migrated into the redirect config in next.config.js
or middleware |
| B10 | Migrate the runtime configuration to use environment variables | - | - | Now: 0%
| You cannot import getConfig
from next/config
in the App Router.
You can instead use environment variables directly in the code.https://nextjs.org/docs/pages/api-reference/next-config-js/runtime-configuration |
| B11 | Migrate away from req
and res
objects in the getInitialProps
function. | - | - | Now: 0%
Soon: 25% | Instead of accessing req
and res
objects, you can use cookies and headers hooks in the server components.
https://nextjs.org/docs/app/api-reference/functions/cookies
https://nextjs.org/docs/app/api-reference/functions/headers |
| B12 | Create the root error page (app/error.tsx
) | App Directory Boilerplate | vscode://intuita.intuita-vscode-extension/showCodemod?chd=nARTEpqaNCsnGw3tnJN6B45fMB0
| Now: 25%
| This step is optional.
If you have pages/_error.
tsx implement, you likely need to copy its contents to app/error.tsx
.
Follow the guide here: https://nextjs.org/docs/app/building-your-application/routing/error-handling |
| B13 | Create the app/not-found.tsx
page | App Directory Boilerplate | vscode://intuita.intuita-vscode-extension/showCodemod?chd=nARTEpqaNCsnGw3tnJN6B45fMB0
| Now: 25%
| This step is optional.
If you have pages/404.tsx
implement, you likely need to copy its contents to app/not-found.tsx
.
Follow the guide here: https://nextjs.org/docs/app/api-reference/file-conventions/not-found |
| C1 | Create a page.tsx
file (the main host for the server components) for each route. | App Directory Boilerplate | vscode://intuita.intuita-vscode-extension/showCodemod?chd=nARTEpqaNCsnGw3tnJN6B45fMB0
| Now: 80%
| https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration#step-4-migrating-pages
For each page, we should create a page.tsx
in an appropriate directory in the app
root directory. This file is a place for the server component logic.
Separate the server-component and client-component logic.
Each page.tsx
should contain a default-exported async function that is a React-Server component.
|
| C2 | Migrate the functionality in every occurrence of getServerSideProps
to everypage.tsx
| Remove Get Static Props | vscode://intuita.intuita-vscode-extension/showCodemod?chd=gqDiMZhaiz_RSzyfHeUueiYcGFI
| Now: 80%
| In every page within the pages
directory, read what getServerSideProps
do and reimplement it by getting the same information directly in the main page.tsx
component. The concept of getServerSideProps
is not applicable in the App router.
https://nextjs.org/docs/pages/api-reference/functions/get-server-side-props |
| C3 | Migrate the functionality in every occurrence of getStaticProps
to everypage.tsx
| Remove Get Static Props | vscode://intuita.intuita-vscode-extension/showCodemod?chd=gqDiMZhaiz_RSzyfHeUueiYcGFI
| 100%
| In every page within the pages
directory, read what getStaticProps
do and reimplement it by getting the same information directly in the main page.tsx
component. The concept of getStaticProps
is not applicable in the App router.
https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration#static-site-generation-getstaticprops |
| C4 | Migrate the functionality in every occurrence of getInitialProps
to everypage.tsx
| - | - | Now: 0%
Soon**: 80%** | In every page within the pages
directory, read what getInitialProps
do (providing the starting props for the server component) and reimplement it in every page.tsx
default React-server component. The concept of getInitialProps
is not directly translatable in the App router.
https://nextjs.org/docs/pages/api-reference/functions/get-initial-props |
| C5 | Reimplement getStaticPaths
as generateStaticParams
in every page.tsx
| Remove Get Static Props | vscode://intuita.intuita-vscode-extension/showCodemod?chd=gqDiMZhaiz_RSzyfHeUueiYcGFI
| Now: 80%
Soon: 90% | Generate static routes at build-time.
https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration#dynamic-paths-getstaticpaths
https://nextjs.org/docs/pages/api-reference/functions/get-static-props
|
| C6 | Implement metadata
object or generateMetadata
function in every page.tsx
, if the page or its child components define meta tags using Next/Head. | Replace Next Head | vscode://intuita.intuita-vscode-extension/showCodemod?chd=HCouE4WzwvH-jcfOJ3xYLz4YaTA
| Now: 100%
| Generate metadata to be consumed by the SEO by declaring an async function called generateMetadata
on the root-level of every page.tsx
, if applicable.
You can also implement an exported metadata
object if you don’t need an async function.
https://nextjs.org/docs/app/api-reference/functions/generate-metadata |
| C7 | Create a components.tsx
file or similar (the main host for the client-rendered page’s component) for every route. | App Directory Boilerplate (work in progress) | vscode://intuita.intuita-vscode-extension/showCodemod?chd=nARTEpqaNCsnGw3tnJN6B45fMB0
| Now: 0% | This file will host a client-side-rendered component.
The file should be tagged with 'use client';
directive at the beginning of it.
The file’s components should be imported in the page.tsx
file in the same directory. |
| C8 | Create a layout.tsx
page for every route, if necessary. | - | - | Now: 0%
| For most projects, a proper layout.tsx
file should be created from the getLayout
function pattern. |
| C9 | Create an error.tsx
page for every route, if necessary. | - | - | Now: 0%
| This step is optional for every route.
Follow the guide here: https://nextjs.org/docs/app/building-your-application/routing/error-handling |
| C10 | Remove the pages directory. | App Directory Boilerplate (partially) | vscode://intuita.intuita-vscode-extension/showCodemod?chd=nARTEpqaNCsnGw3tnJN6B45fMB0
| Now: 25%
| After you have migrated all pages from the pages
directory to the app
directory, you can remove the pages directory. |
| A1 | Extract code blocks and re-export as GET
, POST
, etc. | Replace Route Handlers | | Now: 0%
Soon: 80+% | this step can occur at any order. should this be part of migrator or optimizer? @Dmytro H. |
| A2 | Replace res
and req
with corresponding NextRequest and NextResponse objects | Replace Route Handlers | | Now: 0%
Soon: 80+% | this step can occur at any order |