Skip to content

File-Based Routing

File-based routing is the foundation of both Next.js routers: your folder structure defines your URL structure. This lesson focuses on how that mapping works in detail, using the App Router as the primary example.

Folders Define URL Segments

In the App Router, every folder inside app/ represents one segment of a URL path. A folder named blog inside app/ contributes the /blog segment; a folder named [slug] inside app/blog/ contributes a dynamic segment, matching any value at that position in the URL, like /blog/hello-world.

A folder only becomes an actual, navigable route once it contains a page.tsx (or, for APIs, a route.ts) file. Folders without one of these files can still exist purely for organization — for example, to hold a shared layout.tsx or colocated components — without adding a new URL.

app/
  blog/
    page.tsx          // /blog
    [slug]/
      page.tsx        // /blog/:slug
  dashboard/
    settings/
      page.tsx        // /dashboard/settings
    _components/      // NOT a route (underscore-prefixed = private)
      Sidebar.tsx

Folder names become URL segments; only folders with a page.tsx become visitable routes, and underscore-prefixed folders are excluded from routing entirely.

Naming Conventions That Affect Routing

[slug]           // dynamic segment: /blog/hello-world
[...slug]        // catch-all segment: /docs/a/b/c
[[...slug]]      // optional catch-all: matches /docs too
(marketing)      // route group: organizes without adding a URL segment
_components       // private folder: excluded from routing entirely
  • Square brackets [name] create a dynamic segment accessible via params.name.
  • Three dots inside brackets [...name] create a catch-all segment matching multiple path parts.
  • Double brackets around a catch-all [[...name]] make that segment optional.
  • Parentheses (name) create a route group that organizes files without affecting the URL.

File-Based Routing Cheat Sheet

How different folder and file names map to routing behavior.

Pattern Example Path Matches
about/page.tsx app/about/page.tsx /about
[id]/page.tsx app/posts/[id]/page.tsx /posts/123
[...slug]/page.tsx app/docs/[...slug]/page.tsx /docs/a/b/c
[[...slug]]/page.tsx app/docs/[[...slug]]/page.tsx /docs and /docs/a/b
(group)/page.tsx app/(marketing)/about/page.tsx /about (group is invisible in URL)
_folder/ app/_lib/helpers.ts Not routable at all

Reading Route Parameters

Every dynamic segment is available to a page.tsx component through its params prop, which Next.js provides automatically. Catch-all segments are delivered as an array of strings rather than a single string.

// app/blog/[slug]/page.tsx
export default function BlogPost({
  params,
}: {
  params: { slug: string };
}) {
  return <h1>Post: {params.slug}</h1>;
}

For /blog/hello-world, params.slug is the string "hello-world".

Colocating Non-Route Files Safely

Because only page.tsx and route.ts are treated as routable, you can safely colocate components, tests, styles, and utility files anywhere inside app/ without accidentally creating new URLs — as long as you avoid naming them exactly page.tsx or route.ts.

  • app/blog/PostCard.tsx — a component, not a route.
  • app/blog/utils.ts — a helper file, not a route.
  • app/blog/_internal/ — a private folder, explicitly excluded from routing.

Common Mistakes

  • Naming a component file page.tsx by accident and creating an unintended route.
  • Forgetting that catch-all segments ([...slug]) deliver an array, not a string, in params.
  • Assuming route groups (name) show up in the URL — they are intentionally invisible.
  • Placing shared utilities directly in app/ without an underscore prefix, risking accidental route creation later.

Key Takeaways

  • Folders inside app/ map directly to URL segments; page.tsx is what makes a segment routable.
  • [name] creates dynamic segments; [...name] creates catch-all segments; [[...name]] makes them optional.
  • Route groups (name) organize files without changing the URL structure.
  • Underscore-prefixed folders (_lib, _components) are excluded from routing entirely.
  • Non-special files can be colocated freely inside route folders without becoming routes themselves.

Pro Tip

Adopt a naming convention early — for example, always prefixing non-route helper folders with an underscore — so that as your app/ directory grows, it stays obvious at a glance which folders are real routes and which are just organizational.