We recommend reading the Routing Fundamentals page before continuing.
This page will guide you through how to define and organize routes in your Next.js application.
Inside the app
directory, folders are used to define routes.
Each folder represents a route segment that maps to a URL segment. To create a nested route, you can nest folders inside each other.
A special page.js
file is used to make route segments publicly accessible.
In this example, the /dashboard/analytics
URL path is not publicly accessible because it does not have a corresponding page.js
file. This folder could be used to store components, stylesheets, images, or other colocated files.
Good to know:
.js
,.jsx
, or.tsx
file extensions can be used for special files.
Special file conventions are used to create UI for each route segment. The most common are pages to show UI unique to a route, and layouts to show UI that is shared across multiple routes.
For example, to create your first page, add a page.js
file inside the app
directory and export a React component:
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
Learn more about creating pages and layouts.
The hierarchy of the app
folder maps directly to URL paths. However, it’s possible to break out of this pattern by creating a route group. Route groups can be used to:
A route group can be created by wrapping a folder’s name in parenthesis: (folderName)
To organize routes without affecting the URL, create a group to keep related routes together. The folders in parenthesis will be omitted from the URL (e.g. (marketing)
or (shop)
).
Even though routes inside (marketing)
and (shop)
share the same URL hierarchy, you can create a different layout for each group by adding a layout.js
file inside their folders.
To opt specific routes into a layout, create a new route group (e.g. (shop)
) and move the routes that share the same layout into the group (e.g. account
and cart
). The routes outside of the group will not share the layout (e.g. checkout
).
To create multiple root layouts, remove the top-level layout.js
file, and add a layout.js
file inside each route groups. This is useful for partitioning an application into sections that have a completely different UI or experience. The <html>
and <body>
tags need to be added to each root layout.
In the example above, both (marketing)
and (shop)
have their own root layout.
(marketing)/about/page.js
and (shop)/about/page.js
would both resolve to /about
and cause an error./cart
that uses app/(shop)/layout.js
to /blog
that uses app/(marketing)/layout.js
will cause a full page load. This only applies to multiple root layouts.When you don't know the exact segment names ahead of time and want to create routes from dynamic data, you can use Dynamic Segments that are filled in at request time or prerendered at build time.
A Dynamic Segment can be created by wrapping a folder’s name in square brackets: [folderName]
. For example, [id]
or [slug]
.
Dynamic Segments are passed as the params
prop to layout
, page
, route
, and generateMetadata
functions.
For example, a simple blog could include the following route app/blog/[slug]/page.js
where [slug]
is the Dynamic Segment for blog posts.
export default function Page({ params }) {
return <div>My Post</div>;
}
Route | Example URL | params |
---|---|---|
app/blog/[slug]/page.js | /blog/a | { slug: 'a' } |
app/blog/[slug]/page.js | /blog/b | { slug: 'b' } |
app/blog/[slug]/page.js | /blog/c | { slug: 'c' } |
See the generateStaticParams() page to learn how to generate the params for the segment.
Note: Dynamic Segments are equivalent to Dynamic Routes in the
pages
directory.
Dynamic Segments can be extended to catch-all subsequent segments by adding an ellipsis inside the brackets [...folderName]
.
For example, app/shop/[...slug]/page.js
will match /shop/clothes
, but also /shop/clothes/tops
, /shop/clothes/tops/t-shirts
, and so on.
Route | Example URL | params |
---|---|---|
app/shop/[...slug]/page.js | /shop/a | { slug: ['a'] } |
app/shop/[...slug]/page.js | /shop/a/b | { slug: ['a', 'b'] } |
app/shop/[...slug]/page.js | /shop/a/b/c | { slug: ['a', 'b', 'c'] } |
Catch-all Segments can be made optional by including the parameter in double square brackets: [[...folderName]]
.
For example, app/shop/[[...slug]]/page.js
will also match /shop
, in addition to /shop/clothes
, /shop/clothes/tops
, /shop/clothes/tops/t-shirts
.
The difference between catch-all and optional catch-all segments is that with optional, the route without the parameter is also matched (/shop
in the example above).
Route | Example URL | params |
---|---|---|
app/shop/[[...slug]]/page.js | /shop | {} |
app/shop/[[...slug]]/page.js | /shop/a | { slug: ['a'] } |
app/shop/[[...slug]]/page.js | /shop/a/b | { slug: ['a', 'b'] } |
app/shop/[[...slug]]/page.js | /shop/a/b/c | { slug: ['a', 'b', 'c'] } |
When using TypeScript, you can add types for params
depending on your configured route segment.
export default function Page({
params,
}: {
params: { slug: string };
}) {
return <h1>My Page</h1>;
}
Route | params Type Definition |
---|---|
app/blog/[slug]/page.js | { slug: string } |
app/shop/[...slug]/page.js | { slug: string[] } |
app/[categoryId]/[itemId]/page.js | { categoryId: string, itemId: string } |
Note: This may be done automatically by the TypeScript plugin in the future.