July 10, 2024 · 4 min read · 430 views
Welcome to our detailed guide on migrating from Next.js's traditional Pages Router to the new App Router. This migration is designed to bring your application into a new age of routing efficiency and flexibility. The App Router enhances the developer experience by offering improved file system-based routing capabilities and uses the new React Server Components among other things.
Before we dive into the migration steps, it's important to ensure that your package.json file is updated. Check all dependencies to confirm they are compatible with the new App Router, and upgrade them if necessary. This preliminary step will help avoid potential compatibility issues during the migration process.
You can quickly check with npm
by running:
npm outdated
The first step is to create a new `/app` directory at the root of your Next.js project. This is where you will place all the files and components for the App Router.
The /pages/_document.tsx
file is used to customize the HTML document that is rendered on the server. In the App Router, this functionality is handled by the /app/layout.tsx
file.
Copy the contents of /pages/_document.tsx
into a new file called /app/layout.tsx
.
Remove the next/document
import and replace the <Html>
, <Head>
, and <Main />
components with their HTML equivalents (<html>
, <head>
, and {children}
).
Remove the <NextScript />
component.
For each page in your /pages
directory, you will need to create a corresponding folder structure in the /app
directory.
Create a folder structure in /app
that matches the URL path of your page. For example, if you have a page at /pages/about.tsx
, you would create an /app/about/page.tsx
file.
In the page.tsx
file, copy the contents of your original page component.
If your page component uses any client-side functionality (e.g., hooks, browser APIs), you will need to wrap it with the 'use client'
directive at the top of the file.
In the App Router, the traditional Next.js data fetching methods (getStaticProps
, getServerSideProps
, getStaticPaths
) are no longer used. Instead, you can directly fetch data within your page components.
Remove any getStaticProps
, getServerSideProps
, or getStaticPaths
functions from your page components.
Fetch data directly within your page components using standard JavaScript/TypeScript asynchronous functions.
Before (Pages Router):
// /pages/about.tsx
import { GetStaticProps } from 'next';
export const getStaticProps: GetStaticProps = async () => {
const data = await fetchSomeData();
return {
props: { data },
};
};
const AboutPage = ({ data }: { data: any }) => {
return (
<div>
<h1>About Page</h1>
<p>{data.message}</p>
</div>
);
};
export default AboutPage;
After (App Router):
import { fetchSomeData } from '@/lib/data';
const AboutPage = async () => {
const data = await fetchSomeData();
return (
<div>
<h1>About Page</h1>
<p>{data.message}</p>
</div>
);
};
export default AboutPage;
The App Router introduces new routing hooks that replace the ones used in the Pages Router:
Use useRouter()
, usePathname()
, and useSearchParams()
from next/navigation
instead of useRouter()
from next/router
.
The new useRouter()
hook does not return the pathname
or query
properties. Use usePathname()
and useSearchParams()
instead.
Before (Pages Router)
// /pages/users/[id].tsx
import { useRouter } from 'next/router';
const UserPage = () => {
const { query } = useRouter();
const userId = query.id as string;
return (
<div>
<h1>User Page</h1>
<p>User ID: {userId}</p>
</div>
);
};
export default UserPage;
After (App Router):
// /app/users/[id]/page.tsx
'use client';
import { usePathname, useSearchParams } from 'next/navigation';
const UserPage = () => {
const pathname = usePathname();
const searchParams = useSearchParams();
const userId = searchParams.get('id');
return (
<div>
<h1>User Page</h1>
<p>User ID: {userId}</p>
</div>
);
}
export default UserPage;
The App Router has a different approach to error handling compared to the Pages Router:
Replace the pages/_error.js
file with app/error.tsx
to handle global errors.
Create different error.tsx
files within your page folders to handle specific route-level errors.
Before (Pages Router)
// /pages/_error.js
import { NextPageContext } from 'next';
const ErrorPage = ({ statusCode }: { statusCode: number }) => {
return (
<div>
<h1>Error {statusCode}</h1>
<p>An error occurred on the server</p>
</div>
);
};
ErrorPage.getInitialProps = ({ res, err }: NextPageContext) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
return { statusCode };
};
export default ErrorPage;
After (App Router):
// /app/error.tsx
// Error components must be Client Components!
'use client';
interface ErrorPageProps {
error: Error & { digest?: string }
reset: () => void;
}
const ErrorPage = ({ error, reset }: ErrorPageProps) => {
return (
<div>
<h1>Error</h1>
<p>{error.message}</p>
<button onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}>
Try again
</button>
</div>
);
};
export default ErrorPage;
Depending on your application, you may need to migrate other features, such as API routes, middleware, and custom document/app components. Refer to the Next.js documentation for guidance on how to migrate these features to the App Router.
After completing the migration, thoroughly test your application to ensure all functionality is working as expected. Pay close attention to any differences in behavior between the Pages Router and the App Router.
Remember, the App Router and Pages Router can coexist in the same Next.js application, allowing for an incremental migration approach. This can be helpful if you need to retain certain legacy features that are not yet supported in the App Router.
Migrating from Next.js's Pages Router to the new App Router can enhance your application's routing capabilities and offer more flexibility. By updating dependencies, restructuring your files, and adapting to new data fetching and error handling methods, you can make the most of the App Router's features. Although it requires some effort, the benefits of a more efficient and scalable application are clear.
If you need help with a Next.js or React project let's get in touch.
Lucky Media is proud to be recognized as a Top Next js Development Agency
Technologies:
Related Posts
Stay up to date
Be updated with all news, products and tips we share!