This RFC outlines the biggest update to Next.js since it was introduced in 2016:
- Nested Layouts: Build complex applications with nested routes.
- Designed for Server Components: Optimized for subtree navigation.
- Improved Data Fetching: Fetch in layouts while avoiding waterfalls.
- Using React 18 Features: Streaming, Transitions, and Suspense.
- Client and Server Routing: Server-centric routing with SPA-like behavior.
- 100% incrementally adoptable: No breaking changes so you can adopt gradually.
- Advanced Routing Conventions: Offscreen stashing, instant transitions, and more.
The new Next.js router will be built on top of the recently released React 18 features. We plan to introduce defaults and conventions to allow you to easily adopt these new features and take advantage of the benefits they unlock.
Timeline
This RFC will be divided into two parts:
- Part 1 (This Post): Overview of the new routing system and how it integrates with React Server Components and Data Fetching.
- Part 2 (Next Post): Advanced routing examples and conventions, and how Next.js will use Suspense behind the scenes for streaming and selective hydration.
Motivation
We've been gathering community feedback from GitHub, Discord, Reddit, and our developer survey about the current limitations of routing in Next.js. We've found that:
- The developer experience of creating layouts can be improved. It should be easy to create layouts that can be nested, shared across routes, and have their state preserved on navigation.
- Many Next.js applications are dashboards or consoles, which would benefit from more advanced routing solutions.
While the current routing system has worked well since the beginning of Next.js, we want to make it easier for developers to build more performant and feature-rich web applications.
As framework maintainers, we also want to build a routing system that is backwards compatible and aligns with the future of React.
Note: Some routing conventions were inspired by the Relay-based router at Meta, where some features of Server Components were originally developed, as well as client-side routers like React Router and Ember.js. The
layout.js
file convention was inspired by the work done in SvelteKit. We'd also like to thank Cassidy for opening an earlier RFC on layouts.
Terminology
This RFC introduces new routing conventions and syntax. The terminology is based on React and standard web platform terms. Throughout the RFC, you'll see these terms linked back to their definitions below.
- Tree: A convention for visualizing a hierarchical structure. For example, a component tree with parent and children components, a folder structure, etc.
- Subtree Part of the tree, starting at the root (first) and ending at the leaves (last).

- URL Path: Part of the URL that comes after the domain.
- URL Segment: Part of the URL path delimited by slashes.

How Routing Currently Works
Today, Next.js uses the file system to map individual folders and files in the Pages directory to routes accessible through URLs. Each Page file exports a React Component and has an associated Route based on its file name. For example:

- Dynamic Routes: Next.js supports Dynamic Routes (including catch all variations) with the
[param].js
,[...param].js
and[[...param]].js
conventions. - Layouts: Next.js offers support for simple component-based layouts, per-page layouts using a component property pattern, and a single global layout using a custom app.
- Data Fetching: Next.js provides data fetching methods (
getStaticProps
,getServerSideProps
) which can be used at the page (route) level. These methods are used to determine if a page should be Statically Generated (getStaticProps
) or Server-Side Rendered (getServerSideProps
). In addition, you can use Incremental Static Regeneration (ISR) to create or update static pages after a site is built. - Rendering: Next.js provides three rendering options: Static Generation, Server-Side Rendering, and Client-Side Rendering. By default, pages are statically generated unless they have a blocking data fetching requirement (
getServerSideProps
).
Introducing the App Folder
To ensure these new improvements can be incrementally adopted and avoid breaking changes, we are proposing a new directory called app
.

The app
directory will work alongside the pages
directory. You can incrementally move parts of your application to the new app
directory to take advantage of the new features. For backwards compatibility, the behavior of the pages
directory will remain the same and continue to be supported.
Defining Routes
You can use the folder hierarchy inside app
to define routes. A route is a single path of nested folders, following the hierarchy from the root folder down to a final leaf folder.

For example, you can add a new /dashboard/settings
route by nesting two new folders in the app
directory.
Note:
- With this system, you'll use folders to define routes, and files to define UI (with new file conventions such as
layout.js
,page.js
, and in the second part of the RFCloading.js
).- This allows you to colocate your own project files (UI components, test files, stories, etc) inside the
app
directory. Currently this is only possible with the pageExtensions config.
Route Segments
Each folder in the subtree represents a route segment. Each route segment is mapped to a corresponding segment in a URL path.

For example, the /dashboard/settings
route is composed of 3 segments:
- The
/
root segment - The
dashboard
segment - The
settings
segment
Note: The name route segment was chosen to match the existing terminology around URL paths.
Layouts
New file convention: layout.js
So far, we have used folders to define the routes of our application. But empty folders do not do anything by themselves. Let's discuss how you can define the UI that will render for these routes using new file conventions.
A layout is UI that is shared between route segments in a subtree. Layouts do not affect URL paths and do not re-render (React state is preserved) when a user navigates between sibling segments.
A layout can be defined by default exporting a React component from a layout.js
file. The component should accept a children
prop which will be populated with the segments the layout is wrapping.
There are 2 types of layouts:
- Root layout: Applies to all routes
- Regular layout: Applies to specific routes
You can nest two or more layouts together to form nested layouts.
Root layout
You can create a root layout that will apply to all routes of your application by adding a layout.js
file inside the app
folder.

Note:
- The root layout replaces the need for a custom App (
_app.js
) and custom Document (_document.js
) since it applies to all routes.- You'll be able to use the root layout to customize the initial document shell (e.g.
<html>
and<body>
tags).- You'll be able to use data fetching methods inside the root layout (and other layouts).
Regular layouts
You can also create a layout that only applies to a part of your application by adding a layout.js
file inside a specific folder.

For example, you can create a layout.js
file inside the dashboard
folder which will only apply to the route segments inside dashboard
.
Nesting layouts
Layouts are nested by default.

For example, if we were to combine the two layouts above. The root layout (app/layout.js
) would be applied to the dashboard
layout, which would also apply to all route segments inside dashboard/*
.

Pages
New file convention: page.js
A page is UI that is unique to a route segment. You can create a page by adding a page.js
file inside a folder.

For example, to create pages for the /dashboard/*
routes, you can add a page.js
file inside each folder. When a user visits /dashboard/settings
, Next.js will render the page.js
file for the settings
folder wrapped in any layouts that exist further up the subtree.

You can create a page.js
file directly inside the dashboard folder to match the /dashboard
route. The dashboard layout will also apply to this page:

This route is composed of 2 segments:
- The
/
root segment - The
dashboard
segment
Note:
- For a route to be valid, it needs to have a page in its leaf segment. If it doesn't, the route will throw an error.
Layout and Page Behavior
- The file extensions
js|jsx|ts|tsx
can be used for Pages and Layouts. - Page Components are the default export of
page.js
. - Layout Components are the default export of
layout.js
. - Layout Components must accept a
children
prop.
When a layout component is rendered, the children
prop will be populated with a child layout (if it exists further down the subtree) or a page.
It may be easier to visualize it as a layout tree where the parent layout will pick the nearest child layout until it reaches a page.
Basic Example:

// Root layout (app/layout.js) // - Applies to all routes export default function RootLayout({ children }) { return ( <html> <body> <Header /> {children} <Footer /> </body> </html> ) } // Regular layout (app/dashboard/layout.js) // - Applies to route segments in app/dashboard/* export default function DashboardLayout({ children }) { return ( <> <DashboardSidebar /> {children} </> ) } // Page Component (app/dashboard/analytics/page.js) // - The UI for the `app/dashboard/analytics` segment // - Matches the `acme.com/dashboard/analytics` URL path export default function AnalyticsPage() { return ( <main>...</main> ) }
The above combination of layouts and pages would render the following component hierarchy:
<RootLayout> <Header /> <DashboardLayout> <DashboardSidebar /> <AnalyticsPage> <main>...</main> </AnalyticsPage> </DashboardLayout> <Footer /> </RootLayout>
React Server Components
Note: If you're not familiar with React Server Components, we recommend reading the React Server Component RFC before this section.
With this RFC, you can start using React features and incrementally adopt React Server Components into your Next.js application.
The internals of the new routing system leverage recently released React features such as Streaming, Suspense, and Transitions. These are the building blocks for React Server Components.
Server Components are the new default
One of the biggest changes between the pages
and app
directories is that, by default, files inside app
will be rendered on the server as React Server Components.
This will allow you to automatically adopt React Server Components when migrating from pages
to app
.
Rendering Environments and Component Types
Note: React introduces new component (module) types: Server, Client, and Shared Components. To learn more about these new types, we recommend reading the Capabilities & Constraints of Server and Client Components and Server Module Conventions RFC.
You'll have granular control of what components will be in the client-side JavaScript bundle using the new React conventions. There is an ongoing discussion on what exactly the convention will be for defining Client Components and Server Components. We will follow the resolution of this discussion.
For now, it's worth noting that app
allows components (layouts and pages) in a route to be rendered on the server, on the client, or both.

This is different from the pages
directory in Next.js, where by default, pages are statically generated unless they have data fetching requirements. In pages
, you have the flexibility to decide when (build time or runtime) and where (server-side, client-side, or a combination) a page is rendered by using Next.js data fetching methods (getStaticProps
, getServerSideProps
) or fetching the data from the client-side
However, in the app
folder, the rendering environment is decoupled from the data fetching method and set at the component level. You will still need to respect the constraints of Client and Server components (e.g. you will not be able to use the getServerSideProps
method inside a page or layout that is a client component).
Interleaving Client and Server Components using the children
prop
In React, there's a restriction around importing Server Components inside Client Components because Server Components might have server-only code (e.g. database or filesystem utilities).
For example, importing the Server Component would not work:
import ServerComponent from './ServerComponent.js'; export default function ClientComponent() { return ( <> <ServerComponent /> </> ); }
However, a Server Component can be passed as a child of a Client Component. You can do this by wrapping them in another Server Component. For example:
// ClientComponent.js export default function ClientComponent({ children }) { return ( <> <h1>Client Component</h1> {children} </> ); } // ServerComponent.js export default function ServerComponent() { return ( <> <h1>Server Component</h1> </> ); } // page.js // It's possible to import Client and Server components inside Server Components // because this component is rendered on the server import ClientComponent from "./ClientComponent.js"; import ServerComponent from "./ServerComponent.js"; export default function ServerComponentPage() { return ( <> <ClientComponent> <ServerComponent /> </ClientComponent> </> ); }
With this pattern, React will know it needs to render ServerComponent
on the server before sending the result (which doesn't contain any server-only code) to the client. From the Client Component's perspective, its child will be already rendered.
In layouts, this pattern is applied with the children
prop so you don't have to create an additional wrapper component.
For example, the ClientLayout
component will accept the ServerPage
component as its child:
// The Dashboard Layout is a Client Component // app/dashboard/layout.js export default function ClientLayout({ children }) { // Can use useState / useEffect here return ( <> <h1>Layout</h1> {children} </> ); } // The Page is a Server Component that will be passed to Dashboard Layout // app/dashboard/settings/page.js export default function ServerPage() { return ( <> <h1>Page</h1> </> ); }
Note: This style of composition is an important pattern for rendering Server Components inside Client Components. It sets the precedence of one pattern to learn, and is one of the reasons why we've decided to use the
children
prop.
Data fetching
It's possible to use Next.js data fetching methods inside layout.js
files. This is different from the pages
directory, where data fetching methods were limited to the page-level.
Since layouts can be nested, this also means it is possible to fetch data in multiple segments of a route.
Data fetching in Layouts
You can fetch data in a layout.js
file by using the Next.js data fetching methods getStaticProps
or getServerSideProps
.
For example, a blog layout could use getStaticProps
to fetch categories from a CMS, which can be used to populate a sidebar component:
// app/blog/layout.js export async function getStaticProps() { const categories = await getCategoriesFromCMS(); return { props: { categories }, }; } export default function BlogLayout({ categories, children }) { return ( <> <BlogSidebar categories={categories} /> {children} </> ); }
Multiple data fetching methods in a route
You can also fetch data in multiple segments of a route. For example, a layout
that fetches data can also wrap a page
that fetches its own data.
Using the blog example above, a single post page can use getStaticProps
and getStaticPaths
to fetch post data from a CMS:
// app/blog/[slug]/page.js export async function getStaticPaths() { const posts = await getPostSlugsFromCMS(); return { paths: posts.map((post) => ({ params: { slug: post.slug }, })), }; } export async function getStaticProps({ params }) { const post = await getPostFromCMS(params.slug); return { props: { post }, }; } export default function BlogPostPage({ post }) { return <Post post={post} />; }
Since both app/blog/layout.js
and app/blog/[slug]/page.js
use getStaticProps
, Next.js will statically generate the whole /blog/[slug]
route as React Server Components at build time - resulting in less client-side JavaScript and faster hydration.
Statically generated routes improve this further, as the client navigation reuses the cache (Server Components data) and doesn't recompute work, leading to less CPU time because you're rendering a snapshot of the Server Components.
Behavior and priority
Next.js Data Fetching Methods (getServerSideProps
and getStaticProps
) can only be used in Server Components in the app
folder. Different data fetching methods in segments across a single route affect each other.
Using getServerSideProps
in one segment will affect getStaticProps
in other segments. Since a request already has to go to a server for the getServerSideProps
segment, the server will also render any getStaticProps
segments. It will reuse the props fetched at build time so the data will still be static, the rendering happens on-demand on every request with the props generated during next build
.
Using getStaticProps
with revalidate (ISR) in one segment will affect getStaticProps
with revalidate
in other segments. If there are two revalidate periods in one route, the shorter revalidation will take precedence.
Note: In the future, this may be optimized to allow for full data fetching granularity in a route.
Data fetching and rendering with React Server Components
The combination of Server-Side Routing, React Server Components, Suspense and Streaming have a few implications for data fetching and rendering in Next.js:
Parallel fetching
Next.js will eagerly initiate data fetches in parallel to minimize waterfalls. For example, if data fetching was sequential, each nested segment in the route couldn't start fetching data until the previous segment was completed. With parallel fetching, however, each segment can eagerly start data fetching at the same time.

Since rendering may depend on Context, rendering for each segment will start once its data has been fetched and its parent has finished rendering.
In the future, with Suspense, rendering could also start immediately - even if the data is not completely loaded. If the data is read before it's available, Suspense will be triggered. React will start rendering Server Components optimistically, before the requests have completed, and will slot in the result as the requests resolve.
Partial fetching and rendering
When navigating between sibling route segments, Next.js will only fetch and render from that segment down. It will not need to re-fetch or re-render anything above. This means in a page that shares a layout, the layout will be preserved when a user navigates between sibling pages, and Next.js will only fetch and render from that segment down.
This is especially useful for React Server Components, as otherwise each navigation would cause the full page to re-render on the server instead of rendering only the changed part of the page on the server. This reduces the amount of data transfered and execution time, leading to improved performance.
For example, if the user navigates between the /analytics
and the /settings
pages, React will re-render the page segments but preserve the layouts:

Note: It will be possible to force a re-fetch of data higher up the tree. We are still discussing the details of how this will look and will update the RFC.
Conclusion
We're excited about the future of layouts, routing, and data fetching in Next.js. In the next part of the RFC, we'll discuss:
- Instant Loading States: With server-side routing, rendering and data fetching happens on the server before navigation completes. This makes it important to show loading UI so the application doesn't feel unresponsive. We propose framework level support for instant loading states - inline and global loading indicators and skeletons.
- Offscreen Stashing with Instant Back/Forward: React is planning to add a new
<Offscreen />
component that stores a React tree and its state without rendering it to the screen. Leveraging this component, it should be possible to stash routes that have been visited and pre-render routes before they are visited. Navigation backwards and forwards to these routes should be instant and restore any previously stored state. - Parallel Routes: If you have two or more tab bars on a page, it should be possible to have two or more parallel nested layouts that can be navigated independently, conceptually similar to an
<iframe />
. - Intercepting Routes: Sometimes it's useful to be able to intercept a route from within another page. The URL would normally lead to a different part of the UI but not when it's visited within this context. For example, a tweet that can be expanded and presented inline or a modal photo viewer instead of a standalone gallery.
- Streaming and selective hydration: We will share more details about how a server centric routing, React Server Components, Suspense and streaming combine to enable new routing paradigms and help performance by reducing what is sent to the client and breaking work down into smaller chunks.
Leave comments and join the conversation on GitHub Discussions.