skip to content

In a Next.js App Router project you create the folder app/dashboard/settings/ and put a Settings.tsx component inside it, but visiting /dashboard/settings returns a 404. Why, and what actually makes a folder under app/ a routable URL?

level: juniorimportance: must knowfreq 80%

answer

  1. folders alone are not routes
  2. one reserved filename makes it public
  3. default export required
  4. everything else is just colocated code

basics

~20 s

In the Next.js App Router, folders only define URL segments. A segment becomes reachable only when it contains a page file that default-exports a component (or a route file for an API endpoint). Every other file in the folder is just colocated code.

solid answer

~40 s

Under `app/`, a folder defines a URL segment but does not create a route on its own. Next only serves a segment publicly when that folder contains a `page.tsx` with a **default export** of a React component — or a `route.ts` if you want an API endpoint instead. `Settings.tsx` is just a normal module sitting in that folder, so nothing is mapped to `/dashboard/settings` and Next falls through to the 404. The fix is to add `app/dashboard/settings/page.tsx` that default-exports the UI, importing `Settings.tsx` if you want to keep the component separate. This is also why colocation is safe: tests, hooks, styles and helper components can live next to a route because Next ignores every filename that is not one of its reserved conventions.

go deeper

for a junior

Be ready to state the rule plainly: a folder sets the path, and the page file with a default export is what makes that path render. Recognise the 404 as a missing page file rather than a build problem.

for a middle

Explain the reserved-filename set and why colocated components, hooks and tests in a route folder are never exposed. Walk the diagnosis order: missing page file, missing default export, wrong filename, private folder.

for a senior

Show judgment about where a route's private code lives — colocated beside the segment versus lifted into shared modules — and be able to debug a routing 404 in an unfamiliar codebase without guessing.

for a principal

Own the convention across a large app: how strictly teams colocate, when a route folder is a signal that code should be extracted, and how you keep the routing table readable as the number of segments grows.

## Folders are the URL, files are the behaviour The App Router maps the filesystem to URLs in two separate steps, and mixing them up is the single most common reason a new route "does not exist". **Folders define the path.** Every folder nested under `app/` contributes one URL segment. `app/dashboard/settings/` describes the path `/dashboard/settings`. That is all a folder does — it is a naming device, not a route. **Files define what the segment can do.** Next reserves a small set of filenames inside those folders. Each reserved name attaches one behaviour to the segment it sits in: - `page` — the UI rendered for this exact URL. This is the file that makes the segment publicly routable. - `route` — an HTTP endpoint for this exact URL, used instead of `page` (a segment cannot have both). - `layout` — shared shell wrapping this segment and everything nested below it. - `loading` — fallback UI shown while this segment's content is being prepared. - `error` — error boundary for this segment's subtree. - `not-found` — UI for the not-found case in this subtree. - `template` — like a layout, but with different remount behaviour. All of them accept `.js`, `.jsx`, `.ts` or `.tsx`, and all are lowercase and exact. `Page.tsx`, `pages.tsx` or `index.tsx` are not conventions — they are ordinary modules. ## What a page file must export The page file must have a **default export** that is a React component: ```tsx // app/dashboard/settings/page.tsx import { Settings } from './Settings' export default function SettingsPage() { return <Settings /> } ``` A named export alone is not enough — `export function SettingsPage()` with no default export will fail rather than render. Note also that a page file is a Server Component by default; making it a client module is a separate opt-in and does not change the routing rule. A segment that holds only a `layout.tsx` is still not routable. A layout is a wrapper for children; with no `page` in the segment and no routable child segment, there is nothing to wrap and the URL 404s. The same is true of a folder holding only `loading.tsx` or `error.tsx`. ## Colocation is safe by default Because the reserved names are a closed set, anything else in a route folder is inert. That is a deliberate design decision: the App Router lets you keep a route's private pieces beside it instead of pushing them into a distant `components/` tree. ``` app/ dashboard/ settings/ page.tsx -> /dashboard/settings Settings.tsx colocated component, not a route settings.test.ts colocated test, not a route useSettings.ts colocated hook, not a route ``` None of the colocated files are reachable over HTTP and none appear in the routing table. Only `page.tsx` produces the URL. This is a real difference from the older Pages Router mental model, where every file under `pages/` became a route and helper modules had to live outside it. ## Debugging "my folder exists but the URL 404s" Work through the causes in this order: 1. **No page file in the leaf segment.** The most common case — a component file was created instead. Only `page` (or `route`) makes a segment addressable. 2. **The page file has no default export.** Renaming or refactoring often leaves only a named export behind. 3. **The filename is close but not exact.** `index.tsx`, `Page.tsx`, `page.ts` containing JSX, or a stray extension the project does not compile. 4. **The folder is opted out of routing.** A folder whose name begins with an underscore is private and is excluded from routing along with everything under it, page files included. 5. **You are checking the wrong path.** Intermediate folders that hold no page of their own are fine — they still contribute their segment to deeper URLs — so `/dashboard` 404ing while `/dashboard/settings` works is normal if only the deeper segment has a page file. ## The mental model to carry into the interview Say it as two rules: *folders create the path, reserved files create the behaviour, and `page` is the file that makes a path exist.* Everything else in the folder is code you happened to store there. That single sentence answers the 404, explains why colocation works, and sets up almost every other App Router file-convention question.

  • If a segment has no page file of its own, can URLs below it still work?
    Yes. An intermediate folder contributes its segment to the path regardless of what it contains. `app/dashboard/settings/page.tsx` serves `/dashboard/settings` even when `app/dashboard/` holds no page file at all — in that case `/dashboard` itself 404s while the deeper URL renders normally.
  • What happens if a segment contains both a page file and a route file?
    They conflict: a single URL cannot resolve to both a UI page and an HTTP endpoint, and Next treats it as an error rather than picking one. Choose per segment — `page` when the URL renders UI, `route` when it answers requests programmatically — and put an endpoint that needs its own URL in its own folder.
  • Why does the App Router allow colocation when the Pages Router did not?
    In the Pages Router every module under `pages/` became a route, so helpers had to live elsewhere. The App Router routes on a fixed set of reserved filenames instead, so any other file in a route folder is invisible to routing. That is what makes keeping a route's components, hooks and tests beside it safe.

saying these in an interview costs you the question

  • Says every folder under app/ automatically becomes a URL
  • Names the file index.tsx instead of page.tsx
  • Uses only a named export and expects the page to render
  • Thinks helper files in a route folder get exposed as routes
  • Believes a folder with just layout.tsx is a working route

context