App Router in Next.js 13+ and Layouts

Table of Contents

  1. Introduction
  2. Overview of Next.js 13+ and the App Router
  3. The App Router vs Pages Router
  4. Setting Up the App Router
  5. Layouts in Next.js 13+: Concept and Usage
  6. Dynamic Routes and Nested Layouts
  7. Layouts and Code Splitting
  8. Handling Loading and Error States in Layouts
  9. Best Practices for App Router and Layouts
  10. Conclusion

1. Introduction

With Next.js 13+, App Router introduces a new way of handling routing and layouts. The App Router aims to improve the flexibility and scalability of your React application by introducing nested routing, layouts, and optimized server-side rendering. In this module, we will explore the App Router feature, how it works, how it differs from the traditional Pages Router, and how to utilize layouts for a better user experience and application performance.


2. Overview of Next.js 13+ and the App Router

Next.js 13+ introduced significant improvements, particularly around routing and layouts. The App Router is a new routing system that offers:

  • Nested Routing: Enables defining layouts that apply to specific sections of your app, creating a more modular and scalable structure.
  • Server-Side Rendering (SSR): App Router leverages automatic SSR for routes.
  • Layouts: You can create shared layouts for multiple pages or sections in your app.
  • Optimized Data Fetching: The App Router integrates well with modern data fetching strategies like React Suspense, allowing for more efficient data loading.

3. The App Router vs Pages Router

In traditional Next.js apps, routing was managed using the Pages Router. With the App Router, Next.js has taken a more component-centric approach, where each route is a React component, and you can define layouts and nested routes.

Pages Router:

  • Simple, file-based routing.
  • Each file in the pages/ directory represents a route.
  • Routes are not nested, and layouts are shared across the app.

App Router:

  • Introduces a more flexible and modular structure.
  • Routes are defined inside the app/ directory and can be nested.
  • Layouts can be reused for different parts of your application, improving scalability.
  • Supports React Suspense and Concurrent Rendering, making it easier to load data and components asynchronously.

4. Setting Up the App Router

To start using the App Router in Next.js 13+, you need to structure your project under the app/ directory. Here’s how to set up the App Router in your Next.js app:

  1. Create the app/ directory in the root of your project.
  2. Inside the app/ directory, create files corresponding to different routes, like page.js or layout.js.

For example, here’s how you can define a simple route in Next.js using the App Router:

jsxCopyEdit// app/page.js
export default function HomePage() {
  return <h1>Welcome to the Home Page</h1>;
}

5. Layouts in Next.js 13+: Concept and Usage

Layouts in Next.js 13+ allow you to create reusable structures for different parts of your app. These layouts can be used to wrap pages, reducing the need for repetitive code and improving maintainability.

Creating Layouts:

You can define layouts using layout.js files. A layout file wraps around a page and can be shared across multiple pages or sections. Layouts are automatically applied to their child routes.

Example of a basic layout:

jsxCopyEdit// app/layout.js
export default function RootLayout({ children }) {
  return (
    <div>
      <header>
        <h1>My App</h1>
      </header>
      <main>{children}</main>
      <footer>© 2025 My App</footer>
    </div>
  );
}

In this example, the children prop represents the content of the page being wrapped by the layout.


6. Dynamic Routes and Nested Layouts

One of the key features of the App Router is dynamic routing and nested layouts.

Dynamic Routes:

Dynamic routes can be defined using brackets ([ ]). For example, to create a route for a user profile page, you can do:

jsxCopyEdit// app/users/[id]/page.js
export default function UserProfile({ params }) {
  const { id } = params;
  return <div>User Profile for {id}</div>;
}

Nested Layouts:

Layouts can be nested within each other. For example, you could have a global layout for your site and a specific layout for user profiles:

jsxCopyEdit// app/layout.js (Global Layout)
export default function RootLayout({ children }) {
  return (
    <div>
      <header>Global Header</header>
      <main>{children}</main>
    </div>
  );
}

// app/users/layout.js (User Layout)
export default function UserLayout({ children }) {
  return (
    <div>
      <header>User Profile Header</header>
      <div>{children}</div>
    </div>
  );
}

7. Layouts and Code Splitting

Layouts in the App Router help with code splitting. Each layout can be split into its own chunk, and only the necessary parts are loaded when required. This reduces the initial load time and improves performance.

  • Page-specific code is loaded only when the page is visited.
  • Shared layouts are reused across multiple pages, optimizing resource usage.

For example, if you have a global layout and a user layout, only the code for the user layout will be loaded when the user section is accessed.


8. Handling Loading and Error States in Layouts

Next.js 13+ provides an integrated way to handle loading states and error boundaries in layouts. This makes it easier to handle long-running data fetching or component loading.

Handling Loading States:

You can create a loading UI for specific sections of your app using React Suspense:

jsxCopyEdit// app/users/page.js
import React, { Suspense } from 'react';

const UserList = React.lazy(() => import('./UserList'));

export default function UsersPage() {
  return (
    <div>
      <Suspense fallback={<div>Loading users...</div>}>
        <UserList />
      </Suspense>
    </div>
  );
}

Handling Errors:

Next.js 13+ allows you to handle errors within layouts, ensuring that the application doesn’t crash:

jsxCopyEdit// app/layout.js
export default function ErrorBoundary({ children }) {
  try {
    return <div>{children}</div>;
  } catch (error) {
    return <div>Error loading component</div>;
  }
}

9. Best Practices for App Router and Layouts

Here are some best practices to follow when working with the App Router and layouts:

  1. Organize Routes Clearly: Structure your routes in a way that makes sense for your app. Use nested routes and layouts to create modular, reusable components.
  2. Use Dynamic Routing Wisely: Only use dynamic routes when necessary to avoid unnecessary complexity.
  3. Optimize Layouts for Performance: Leverage code splitting to ensure that layouts are optimized and only necessary code is loaded.
  4. Handle Errors Gracefully: Always implement error boundaries to prevent crashes and ensure a better user experience.
  5. Leverage Suspense for Async Data: Use React Suspense to handle async data fetching and show loading states where applicable.

10. Conclusion

The App Router in Next.js 13+ provides a more flexible and scalable routing system compared to the traditional Pages Router. By leveraging features like nested routing, dynamic routes, layouts, and React Suspense, you can build complex, performance-optimized applications. Properly managing layouts allows you to share components across pages, improving maintainability and reducing code duplication. Understanding when to use these features will help you take full advantage of Next.js’s capabilities to build modern web applications.