Migrate from Nextjs Pages to App Router

lokman musliu
Lokman Musliu

July 10, 2024 · 4 min read · 430 views

next js 15 deployment

Upgrading your Next.js project

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 start: Please check your dependencies

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

Step 1: Create the `/app` directory

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.

Step 2: Move files from Pages Folder to App Folder

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.

Step 3: Migrate pages to the App Router

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.

Step 4: Update data fetching

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.

Example 1: Fetching data

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;

Step 5: Migrate routing hooks

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.

Example 2: Migrating routing hooks

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;

Step 6: Update error handling

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.

Example 3: Migrating error handling

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;

Step 7: Migrate other features

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.

Step 8: Test and verify

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.

Next.js 15 release date

Conclusion

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.


Bring Your Ideas to Life 🚀

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

lokman musliu
Lokman Musliu

Founder and CEO of Lucky Media

Technologies:

Next.js
Heading Pattern

Related Posts

Stay up to date

Be updated with all news, products and tips we share!