How to use the Next.js app directory: Complete guide and tutorial

Published on January 17, 2025

How to use the Next.js app directory: Complete guide and tutorial

The Next.js app directory changes how you build Next.js apps, and it's all for the better. Next.js is one of the most popular JavaScript web frameworks, providing a foundation for building websites that includes routing, page rendering, and working with APIs.

This guide explains the Next.js App Router, the new way of building Next.js apps introduced in Next.js 13. It covers how the App Router simplifies development and improves your code structure, explains how it differs from the old Pages Router that it replaces, and provides tutorial steps demonstrating how to build apps using the Next.js app directory.

What is the Next.js app directory?

The app directory is a directory in the file system in projects created using Next.js 13 and onwards. Within this directory, you can place subdirectories containing components, layouts, and pages, which are automatically turned into routes. This both speeds up development and enforces structure in your projects, making your code easier to understand and maintain.

What the app directory brings to Next.js

The Next.js app directory (part of the new Next.js App Router) replaces the Pages Router from earlier versions. While the Pages Router is still available, so that existing projects can be updated to Next.js 13 and beyond without breaking, you should use the new App Router for all new projects going forward (and consider moving your old projects over to it if you plan on supporting them for a while).

How it was before: The problems with the Next.js Pages Router

While Next.js (and the Pages Router) generally fulfilled its goal of streamlining the development of web applications, some problems emerged for developers that required reworking the structure of the framework.

Some of the common problems developers would encounter with the old Pages Router structure included:

  • Poor code organization: Managing layouts, data handling, and routes separately made it difficult to write code using the Pages Router that respected the principle of DRY (don't repeat yourself), making code overly complex and difficult to maintain.

  • Poor reusability: The code for page layouts had to be duplicated or shared by manually creating wrapper components, adding development complexity.

  • Clunky data fetching for server-side rendering (SSR): Data fetching could only be done per page. This was inefficient, leading to duplicated code, having to repeat requests (or write additional code to share data between pages).

  • Sequential page rendering: Complex pages rendered slowly as they were rendered sequentially. Partial rendering and streaming of pages was not supported at all using the Pages Router.

How the Next.js App Router solves these problems

The Next.js App Router directly addresses these developer pain points by updating Next.js to better handle more complex applications. This included introducing the new app directory structure and adding new features, including:

  • The Next.js app directory structure: Layouts, routes, and pages are all organized in the app directory so that subdirectories contain files related to the same pages or components. This hierarchical layout separates functionality, makes code easier to navigate and understand, and reduces the amount of boilerplate that needs to be written. Nested layouts can be reused, and enable more modular code, allowing for the easier creation and maintenance of complex applications.

  • Support for React Server Components: Components can be rendered on the server, reducing the amount of client-side code that needs to be loaded and improving performance by delivering smaller bundles.

  • Flexible (and shared!) data fetching: Data can be fetched on the server and shared between components, reducing the number of API calls required, and preventing the need to duplicate code. Caching and revalidation is also available to further improve performance by caching the results of a function.

  • Support for parallel rendering and streaming: Parallel rendering and streaming are natively supported by the App Router. This allows for mandatory components to be rendered first, and subsequent components to be streamed to the client, decreasing page load times.

These updates and new features provided by the Next.js App Router and app directory benefit both developers, and the users of the apps they create. For developers, code is more organized and reusable (and they have to write less of it for the same result), while users benefit from faster apps with better compatibility.

Next.js app directory structure and elements visualized

The below diagram shows the structure of the Next.js app directory and gives an example of its contents. This example has four pages: the home page (located at /), an about page, a news page, and a nested page for international news at news/world.

Next.js app directory

The structure of this application is clearly visible in the structure of the files in the app directory. This makes the purpose of each directory and the files in it clear and easy to navigate. Routes are automatically generated based on the name of the subdirectory paths.

The App Router utilizes inheritance, where the file in the top level acts as the default and each subdirectory contains its own logic that builds on it. For example, the layout.js file in the root of the app directory is the default layout, and others can be created for sub-routes that override it.

Each route directory can contain the following files:

  • layout.js contains the visual layout for the pages in the current directory.

  • page.js specifies the content or functionality for a specific route. The code in this file is executed when the route is accessed, based on the directory path.

  • The loading screen displayed to the user while the page loads can be modified by modifying the loading.js file.

  • Error handling and display can be customized by editing error.js.

Dynamic routes can also be defined by adding subdirectories named with square brackets ([]). The below example adds a blog route with a dynamic route for accessing each individual blog post.

Next.js app directory with added dynamic routes

The contents of the app directory above also define an API route. API routes must include a file named route.js containing route logic that handles a HTTP request, instead of the page.js file that renders a page, as required by normal routes.


The public directory contains static files that you want to serve to users and sits outside of the app directory (in the project root directory). This example includes a favicon and a logo image file. These files do not undergo processing, are all publicly accessible, and should be used for images, icons, and other design elements in your application.


Once you're comfortable with these basics, you can further split and optimize your code by leveraging advanced features like route groups and private folders.

Tutorial: how to use the Next.js app directory

To demonstrate the Next.js app directory, and how it's used with the App Router, you can follow the below steps to create a basic shopping list app in Next.js. You'll need the latest version of Node.js installed.

Create a blank Next.js project

To start, create a new Next.js project by running:

npx create-next-app@latest shoppingapp

Make sure you answer Yes when asked whether to use the App Router (or you won't get very far in this tutorial). Then, navigate to the app directory in the new project:

cd shoppingapp/app

You may need to navigate instead to shoppingapp/src/app if you elected to use the src directory when creating your Next.js app.

At any point in this tutorial, you can test your code by running:

npm run dev

To view your app, open your web browser to http://localhost:3000.

Create a route

Create a shopping-list route, and create layout.js and page.js files for it:

mkdir shopping-list

touch shopping-list/layout.js shopping-list/page.js

Edit these pages to contain the following code:

Note the inclusion of a Link component to create a button for the nested route for adding items created in the next step.

Create a nested route

Create a nested route for shopping-list/add-item like this:

mkdir shopping-list/add-item

touch shopping-list/add-item/page.js

This route will be used with a client-side component to add items to the shopping list. Note that there is no need for a layout.js file as it will be inherited from the parent directory.

Using client components

Create a Next.js client-side component for adding an item to the list:

touch shopping-list/add-item/addItem.js

Add the following code to the file:

Then, add the following code to shopping-list/add-item/page.js to use the component:

To keep this example simple and focused on routing, this component doesn't actually update the main list.

Client components must always start with "use client" (including the quotes).

Loading and error states

Create loading and error states for the shopping-list route and its children:

touch shopping-list/loading.js shopping-list/error.js

And add the following code to each file respectively:

Note that error.js is a client-side component and must contain "use client" (again, with quotes) at the beginning of the file.

Adding parallel routes

Parallel routes are rendered independently within the same layout, so that they don't hold each other up while loading. Create a parallel route for staple shopping list items by running:

mkdir shopping-list/@staples

touch shopping-list/staples/page.js

Parallel routes must be created with a directory prepended with @ to define the slot name that they will be referred to in your layout file. The @ symbol will not be reflected in any route names/URLs.

Then, add the following code to shopping-list/staples/page.js

Finally, replace the contents of shopping-list/layout.js with the following code that adds the parallel route under <main>{children}</main>:

Note that staples has been passed as a prop to ShoppingListLayout.

Fetching data

Finally, we can add a message of the day from a public API to demonstrate how data can be retrieved using the Next.js fetch function, and shared between components.

Replace the contents of shopping-list/page.js with the following code that retrieves some placeholder text and adds it to the page:

When used in the Next.js app directory, fetch will run server-side by default.

Create a route group

You can organize your code by creating a route group to contain all of the example code from this tutorial. This route won't be used in public URLs, and is just for organizing your code:

mkdir "(example)"

mv shopping-list "(example)"

The above commands will create a route group directory named (example) and move the shopping-list directory into it.

Make sure you include the quotes — brackets are special characters in terminal commands.

The URL for the pages created earlier will still be /shopping-list, as the route group directory (example) is not used for generating route URLs.

Once you've got an example working, you can learn more about the Next.js App Router by seeing how it can be integrated with Contentful to build a simple knowledge base app.

​​Next.js app folder structure best practices

  • Stay organized! Route groups can be created by placing routes in a folder named using parentheses [for example, app/(new_routes)] to organize routes without affecting their URL path. You should also be consistent when naming files — it's convention in Next.js projects to use only lower-case alphanumeric characters and dashes (for example, news/local-news).

  • Keep it together by colocating your files: keep everything relating to a route in one place (including layouts, tests, and logic) so that it's easy to find and its purpose is evident when browsing your project.

  • Use private folders to store utility functions and components by preceding a directory name with an underscore (for example, app/_utils). Centralizing shared logic makes it easy to reuse and maintain code.

  • Create a src directory in the root of your project and move your app directory into it to make it clear where your application code lives. When creating a new Next.js project, you'll be prompted whether you want this done for you automatically.

  • Reuse everything you can: The App Router and app directory were created to make it easier to build apps by reducing the amount of code you need to write with features like nested layouts — don't miss out on this benefit by sticking to old habits!

  • Handle errors and loading states using the error.js and loading.js files. Not every route will want to deal with errors or loading issues in the same way, so leverage the App Router’s ability to handle errors and loading for each route distinctly, and provide your users with an appropriate level of feedback or action to take to resolve a problem.

To see these best practices in action, you can follow our guide for building a blog using Next.js, Tailwind CSS, and Contentful.

Make Next.js apps super fast: Static apps + Contentful

Next.js was built so that developers could create better, more reliable web applications in less time, and it delivers on this promise with the new App Router and app directory.

Contentful provides a fully customizable back end for your Next.js apps. Rather than building and maintaining your own content delivery infrastructure, Contentful lets you model your application content, and then provides a complete web-based management interface for creating and maintaining the content for your Next.js apps. Everything can be customized for your requirements, and you can even set up live previews so you can see exactly how your published content will look to your users.

You can even share your content across mobile apps, websites, and other channels, streamlining and centralizing the content creation and curation process.

Subscribe for updates

Build better digital experiences with Contentful updates direct to your inbox.

Meet the authors

David Fateh

David Fateh

Software Engineer, Contentful

David Fateh is a software engineer with a penchant for web development. He helped build the Contentful App Framework and now works with developers that want to take advantage of it.

Related articles

Optimize your images by using the Next.js Image Component. Achieve faster load times, better UX, and scalability, with a more enjoyable developer experience.
Guides

How to optimize images with the Next.js Image Component

August 8, 2024

When deciding between Svelte vs. React for your project, you need to weigh up the performance and developer features of each. This guide will help you choose.
Guides

Svelte vs. React: Choosing the best for features and performance

March 9, 2023

Tagging your images for SEO is the process of applying HTML attribute tags to images in order to help search engines understand the content of your images.
Guides

What is image tagging for SEO?

May 24, 2022

Contentful Logo 2.5 Dark

Ready to start building?

Put everything you learned into action. Create and publish your content with Contentful — no credit card required.

Get started