Defining Routes

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.

Creating Routes

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.

Folders map to URL Segments

A special page.js file is used to make route segments publicly accessible.

Page files 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.

Creating UI

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.

Route Groups

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:

  • Organize routes without affecting the URL structure.
  • Opting-in specific route segments into a layout.
  • Create multiple root layouts by splitting your application.


A route group can be created by wrapping a folder’s name in parenthesis: (folderName)

Example: Organize routes without affecting the URL path

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)).

Organizing routes without affecting the URL path

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.

Multiple layouts in the same hierarchy

Example: Opting specific segments into a layout

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).

Opting into a Layout

Example: Creating multiple root layouts

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.

Creating multiple root layouts

In the example above, both (marketing) and (shop) have their own root layout.

Good to know

  • The naming of route groups has no special significance other than for organization. They do not affect the URL path.
  • Routes inside route groups should not resolve to the same URL path. For example, since route groups don't affect URL structure, (marketing)/about/page.js and (shop)/about/page.js would both resolve to /about and cause an error.
  • Navigating across multiple root layouts will cause a full page load (as opposed to a client-side navigation). For example, navigating from /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.

Dynamic Segments

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>;
RouteExample URLparams
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.

Catch-all Segments

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.

RouteExample URLparams
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'] }

Optional Catch-all Segments

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).

RouteExample URLparams
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: { slug: string };
}) {
  return <h1>My Page</h1>;
Routeparams 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.

Next Steps