Migrating from Next.js Pages Router to App Router
Tags: aws, nextjs, javascript, tutorial
Published: 2023-05-26 22:44:57


## Summary

Migrating from [**`Next.js Pages router`**](https://nextjs.org/docs/pages) to [**`Next.js App router`**](https://nextjs.org/docs/app) provides several benefits and introduces new concepts for organizing your Next.js project. In this guide, we will walk you through the process of migrating to the **`App router`**, explaining important concepts and highlighting key steps along the way. We will also explore the integration of **`Tailwind CSS`** into the project.

---

## Introduction

**`Next.js`** is a popular React framework for building server-side rendered and static websites. With the introduction of the **`App router`**, Next.js offers a more structured approach to organizing your application's routes and components. This migration guide will help you understand the steps involved in adopting the **`Next.js App router`** and using it alongside **`Tailwind CSS`**.

---

## Prerequisites

Before we begin, make sure you have the following requirements in place:

- Node.js 16.8+ installed on your system.
- A basic understanding of Next.js and Tailwind CSS.

---

## Step 1: Installing Required Packages

To get started, navigate to your **`Next.js project directory`** and install the latest required packages for **Next.js** and **Tailwind CSS**. Open your terminal and run the following command:

```bash
npm install next@latest react@latest react-dom@latest tailwindcss@latest
```

This command will update your project with the latest versions of Next.js, React, React DOM, and Tailwind CSS.

---

## Step 2: Updating the Next.js and Tailwind Configuration


Next, we need to update the Next.js configuration to enable the App directory and configure Tailwind CSS accordingly. Locate the [`next.config.js`](https://github.com/albac/albac.dev/blob/main/next.config.js#L4-L6) file in your project and add the following lines:

```javascript
module.exports = {
  experimental: {
    appDir: true,
  },
  // Other configuration options...
};
```

Enabling the **`appDir`** option allows Next.js to recognize the App directory as the main directory for your application's routes.

Now, open the [`tailwind.config.js`](https://github.com/albac/albac.dev/blob/main/tailwind.config.js#L4) file and update the `content` property as follows:

```javascript
module.exports = {
  // Other configuration options...
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./app/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
};
```

This change ensures that Tailwind CSS scans the App directory for CSS utility classes.

---

## Step 3: Creating First App Page Component and Root Layout

To take full advantage of the App router, we need to reorganize our directory structure and create the initial App page component and root layout.

1. Create a new directory called `app` in your project's root directory. This directory will hold your App-specific components and files.

2. To avoid conflicts with new App router files, rename the existing `pages` directory to `old-pages` or choose a different name that is distinct from the default `pages` directory.

3. Edit the `page.tsx` file inside the `app` directory with a simple React component representing your homepage:

   ```javascript
   import React from 'react';

   export default function HomePage() {
     return <div>This is my new App Route Home Page</div>;
   }
   ```

4. Start your Next.js development server using the `npm run dev` command. This will generate the

 `layout.tsx` file automatically for you.

   ```bash
   $ npm run dev
   ...
   wait - compiling /page (client and server) ...
   Your page app/page.tsx did not have a root layout. We created app/layout.tsx for you.
   ```

   After the server starts, your project structure should look like this:

   ```
   - app
     - index.tsx
     - layout.tsx
   ```

5. Since we now have a root layout file, we can add our Tailwind CSS styles to it. Open the `layout.tsx` file and import the `globals.css` file:

   ```javascript
   import '../styles/globals.css';
   ```

---

## Step 4: Naming Convention

The App router follows a naming convention for its files. The files should be named **`page.tsx`**, **`layout.tsx`**, **`loading.tsx`**, etc., depending on their purpose. This convention helps Next.js identify and associate the components correctly with their routes.

---

## Step 5: Understanding Layouts

The `layout.tsx` file in the App directory serves as a global layout for all child views. This means that any components placed in the layout file will be shared across multiple pages unless you create a new layout specifically for a particular page or group of pages. The layout file is an excellent place to define global settings, such as importing global libraries or configuring services like AWS Amplify.

For example, you can configure AWS Amplify in the [`layout.tsx`](https://github.com/albac/albac.dev/blob/main/app/layout.tsx#L22-L28) file as follows:

```javascript
import awsconfig from '../src/aws-exports';
import { Amplify, AuthModeStrategyType } from 'aws-amplify';

Amplify.configure({
  ...awsconfig,
  ssr: true,
  DataStore: {
    authModeStrategyType: AuthModeStrategyType.MULTI_AUTH,
  },
});

interface RootLayoutProps {
  children: React.ReactNode;
}

export default async function RootLayout({ children }: RootLayoutProps) {
  return (
    <html lang="en">
      <body>
        {children}
      </body>
    </html>
  );
}
```

The layout component is responsible for rendering the shared structure, such as the HTML and body tags, while the **`children`** prop represents the content specific to each page.

---

## Step 6: Using the "use client" Directive

By default, all code within the App router runs on the server. To execute code on the client-side, such as React hooks, you need to use the `"use client"` directive at the beginning of your document.

For example, in `app/page.tsx`, you can use the `"use client"` directive and implement a simple counter:

```javascript
"use client"

import { useState } from "react";

export default async function Page() {
  const [counter, setCounter] = useState(0);

  return (
    <div>
      <p>Counter: {counter}</p>
      <button onClick={() => setCounter(prev => prev + 1)}>+1</button>
    </div>
  );
}
```

The `"use client"` directive indicates that this code should run on the client-side, allowing the use of client-specific features like React hooks.

---

## Step 7: Sending Components to the Client

The App router provides a convenient way to send only the necessary components to the client. This approach improves performance by reducing the amount of code sent to the browser.

For example, you can fetch data on the server and render a specific component on the client:


```javascript
// All this code will be executed on the server

import { withSSRContext } from 'aws-amplify';
import { serialize } from 'next-mdx-remote/serialize';
import { Posts } from '../../../src/models';
import Post from '../../../components/Post';

async function fetchPost(slug) {
  const { DataStore } = withSSRContext();
  const post = await DataStore.query(Posts, slug);
  const mdxSource = await serialize(post.content);

  return {
    date: post.createdAt,
    title: post.title,
    content: mdxSource,
    slug,
  };
}

export default async function SlugPage({ params }) {
  const { slug } = params;
  const post = await fetchPost(slug);

  // The <Post/> component will be rendered on the client-side, as we use "use client" within it.
  return <Post {...post} />;
}
```

Another good example, it is our [`Root Layout Component`](https://github.com/albac/albac.dev/blob/main/app/layout.tsx).

The Root Layout is a server component that calls the NavBar and AuthBtn components.

**AuthBtn Component** use the **`useAuthenticator`** hook which can only work on client components.

We call the [`AuthBtn component`](https://github.com/albac/albac.dev/blob/main/components/AuthButton.tsx) from our [`NavBar component`](https://github.com/albac/albac.dev/blob/main/components/Navbar.tsx#L147). Both are client components.

**AuthBtn component**:

```javascript
"use client";

import Link from "next/link";
import { useAuthenticator } from "@aws-amplify/ui-react";
import { Auth } from "aws-amplify";

export default function AuthBtn({ setter }) {
  const { authStatus } = useAuthenticator((context) => [context.authStatus]);

  return (
    <>
      {authStatus && authStatus !== "authenticated" ? (
        <SignInButton setter={setter} />
      ) : (
        <SignOutButton setter={setter} />
      )}
    </>
  );
}

```

This approach ensures that only the necessary components are sent to the client, reducing the initial load time and improving the overall performance of your application.

For more details information about client components go to [https://nextjs.org/docs/getting-started/react-essentials#the-use-client-directive](https://nextjs.org/docs/getting-started/react-essentials#the-use-client-directive).

---

## Step 8: Leveraging SEO Metadata

The App router provides a convenient way to handle metadata, such as page titles, descriptions, and keywords. You can export metadata from your views and layouts to ensure proper SEO optimization.

In your view components, export the metadata as follows:

```javascript
export const metadata = {
  title: 'App Route',
  description: 'First metadata in app route',
  keywords: ['react', 'nextjs'],
};
```


You can also define general metadata in your layout component. Next.js is intelligent enough to prioritize view-specific metadata over layout metadata.


```javascript
export const metadata = {
  title: 'App Route',
  description: 'First metadata in app route',
  keywords: ['react', 'nextjs'],
};

export default function Layout({ children }) {
  return (
   

 <main>
      {children}
    </main>
  );
}
```

By leveraging metadata, you can improve the search engine visibility and discoverability of your application's pages.

---

## Our Website running NextJS App Router

See our current Website laveraging App Router in our github repo: https://github.com/albac/albac.dev

Look at our current structure to see how we organize your pages and components:

```bash

app/api/davinci:
route.ts

app/api/turbo:
route.ts

app/blog-edit:
[id]/

app/blog-edit/[id]:
page.tsx

app/chatgpt:
[model]/

app/chatgpt/[model]:
page.tsx*   layout.tsx

app/legal:
privacy-policy/   terms-conditions/

app/legal/privacy-policy:
page.tsx

app/legal/terms-conditions:
page.tsx

app/projects:
loading.tsx  page.tsx

app/signin:
page.tsx

app/storagemanager:
page.tsx*

app/profile:
loading.tsx        image-profile.tsx  page.tsx

```

---

## Conclusion

Migrating to the Next.js App router introduces a more structured approach to organizing your application's routes and components, making it easier to build and maintain complex applications. In this guide, we specifically looked at how you can migrate a blog application to the App router.

By migrating your blog application to the Next.js App router, you gain a more structured and organized approach to building your blog. The separation of concerns, client-side rendering capabilities, and SEO optimization features provided by the App router enhance the overall user experience and make your blog more efficient and discoverable.

We hope this guide has been helpful in understanding and implementing the Next.js App router in your blog application. For more detailed information and examples, refer to the official Next.js documentation on https://nextjs.org/docs/app.

---

## References

- **Next.js Documentation App**: [https://nextjs.org/docs/app](https://nextjs.org/docs/app)
- **Next.js Official Migration Documentation**: [https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration](https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration)
- **Amplify Documentation: Use Amplify with Next.js App Router (App Directory)**: [https://docs.amplify.aws/lib/ssr/q/platform/js/#use-amplify-with-nextjs-app-router-app-directory](https://docs.amplify.aws/lib/ssr/q/platform/js/#use-amplify-with-nextjs-app-router-app-directory)

---