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.

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.

Dynamic Segments

When you don't know the exact segment names ahead of time and want to create routes from data, you can use Dynamic Segments alongside the generateStaticParams() function.


A Dynamic Segment can be created by wrapping a folder’s name in square brackets: [folderName].


For example, for blog posts, you can create the following route app/blog/[slug]/page.js where [slug] is the Dynamic Segment.

export default function Page({ params, searchParams }) {
  // /blog/hello-world => { params: { slug: 'hello-world' } }
  // /blog/hello-world?id=123 => { searchParams: { id: '123' } }
  return <p>{params.slug}</p>;

When using TypeScript, you can add types for params and searchParams depending on your route segment and expected URL search params:

export default function Page({ params, searchParams }: {
  params: { slug: string },
  searchParams: { id: string },
}) {
  return (

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 and Optional Catch-all Segments

Dynamic Segments can be extended to catch-all by adding an ellipsis inside the brackets [...folderName].

For example, app/blog/[...slug]/page.js can match /blog/a, but also /blog/a/b, /blog/a/b/c, and so on.

Catch-all Segments can be made optional by including the parameter in double square brackets: [[...folderName]].

For example, app/blog/[[...slug]]/page.js will match /blog, /blog/a, /blog/a/b, and so on.

The main difference between catch-all and optional catch-all segment is that with optional, the route without the parameter is also matched (/blog in the example above).

Next Steps