Search⌘ K
AI Features

Creating Routes and Layouts

Explore how to create routes and nested layouts in Next.js using the App Router. Understand mapping page files to routes, building persistent UI with layouts, and implementing nested structures to enhance app performance and user experience.

Routing is the core part of any web app and in Next.js, the App Router makes it both powerful and intuitive.

In this lesson, we’ll see how page.js files map directly to routes, and how layout.js organize the UI by wrapping groups of related pages. These patterns lay the groundwork for building well-structured and fast apps.

Creating a basic route

Let’s start by creating a simple route inside the app/ directory. Every page.js file inside the app/ folder or any of its subfolders automatically becomes a new route.

For example, we can define a React component in the app/about/page.js file to serve as the content for the /about route.

// app/about/page.js
export default function AboutPage() {
return <h1>About us</h1>;
}
Defining a static route using page.js

Under the hood, Next.js detects the app/about/page.js file and registers it as the /about route. No configuration or route definitions are needed.

To create a nested route like /about/team, we can place a new page.js file inside a nested folder:

Folder structure for a nested /about/team route
Folder structure for a nested /about/team route

Then we define a component in app/about/team/page.js to handle the /about/team route:

// app/about/team/page.js
export default function TeamPage() {
return <h1>Meet the team</h1>;
}
Creating a nested route

Why layouts matter

Layouts in Next.js let us define parts of the UI that stay visible while navigating between different pages like a header, sidebar, or footer. These parts don’t unmount or reset when the route changes. Think of a layout as the “shell” of an app: a stable frame that wraps different pages as users move through the site. This behavior not only creates smoother transitions but also improves performance and lets us share logic, like data loading or authentication, across related pages.

Creating the root layout

To display persistent elements like a header or footer, we can define a layout at the root of our app using app/layout.js. This is called the root layout, which acts as the template for the entire application.

// app/layout.js
export default function RootLayout({ children }) {
return (
<html>
<body>
<header>My App</header>
<main>{children}</main>
<footer>© 2025</footer>
</body>
</html>
);
}
A root layout with shared structure

Here are the key things we need to understand about it:

  • Required HTML structure: The root layout must include the <html> and <body> tags, because it creates the main HTML document in which all pages are rendered.

  • The children prop: The layout component must accept a children prop. Think of this as the entry point for all pages; it’s the placeholder where Next.js will render the active page or any nested layouts.

  • Shared UI: The example above includes a <header> and <footer> to represent UI that persists across routes, such as navigation bars or footers.

  • Persistent UI and state: Next.js reuses the layout across navigations. This means shared UI elements like a header or footer don’t rerender, preserving their state and making page transitions feel instant. The example above includes a <header> and <footer> to represent UI that’s shared across routes.

Creating a nested layout

Let’s say we want all pages in the about/ folder to share a custom sidebar. We can do this by adding a layout to that folder.

// app/about/layout.js
export default function AboutLayout({ children }) {
return (
<section>
<aside>About Menu</aside>
<div>{children}</div>
</section>
);
}
A section-specific layout for /about routes

This layout uses an <aside> element (line 5), which is commonly used for secondary content such as navigation, sidebars, or supplementary information.

This layout will be applied to:

  • /about,

  • /about/team, and

  • Any other route under /about.

Nested layouts stack based on the folder structure. In this case, the root layout wraps the about layout, which then wraps the individual page. This allows us to build nested UIs with persistent wrappers at each level.

Layout composition in action

Here’s a quick look at the file structure and how it maps to our app:

app/
layout.js --> Wraps the entire app
about/
layout.js --> Wraps all /about/* pages
page.js --> The /about page
team/
page.js --> The /about/team page
Nested layout and page files defining the /about/team route

When a user visits /about/team, the layout and page components are composed into what’s called a render tree, a nested structure of everything that’s rendered on the page.

<RootLayout>
<AboutLayout>
<TeamPage />
</AboutLayout>
</RootLayout>
Render tree showing how layouts and page components are nested at /about/team

Each layout persists while only the page component changes. This improves performance and provides a seamless experience.

Try it yourself

We have put together the layouts for both routes in the following widget. Once executed, the resulting app is hosted at the link displayed below the widget.

export default function HomePage() {
  return <h1>Home page!</h1>;
}
Running example: Build routes and nested layouts using the App Router in Next.js

Notice that navigating between /about and /about/team does not unmount the layout, the header, footer, and sidebar content stays exactly where it is. Only the content inside the <h1> element changes based on the route.

If you navigate back to /, you’ll still see the same header and footer, but the sidebar disappears because it only exists in the /about layout.

Best practices for using layouts

When working with layouts in Next.js, we start by defining the global structure in layout.js. This is where we set up the main <html> and <body> elements, along with any site-wide UI such as headers or footers.

For sections of the site that need their own structure, we can introduce nested layouts. These are useful for sidebars, breadcrumbsIn UI/UX, a breadcrumb (or breadcrumb navigation) is a trail of links that shows where the user is in the site’s hierarchy, like a path from the home page to the current page. Example: Home / Products / Electronics / Cameras, or any logic tied to a specific part of the application.

We usually avoid duplicating layout elements inside individual page.js files. Instead, we define shared UI once in a layout so it stays persistent across navigation.

Finally, when several routes need the same layout but don’t share the same URL path, we can organize them with route groups, which we’ll explore later.

Key takeaways:

  • Every page.js file under app/ becomes a routable page.

  • Layouts (layout.js) define persistent UI that wraps pages and don’t remount between navigations.

  • Layouts can be nested, allowing different sections of your app to have distinct structures.

  • Use layouts to colocate shared UI and logic, such as navigation menus.

Exercise: Creating a section with shared layout

  1. Define a new route at /team that displays the text: “Welcome to the team.”

  2. Wrap this route in a layout that includes a sidebar labeled “Team Navigation.” The sidebar should be part of a persistent layout that remains visible alongside the page content.

  3. Add a nested route at /team/roles to confirm that the layout persists across subpages.

When navigating between /team and /team/roles, confirm that:

  • The sidebar stays in place.

  • Only the main page content changes based on the route.

export default function HomePage() {
  return <h1>Home page!</h1>;
}
Working with shared layouts

You can view the complete solution by clicking the “Show solution” button.