Private Folders & Colocation
_folderName — and Next.js treats it, and everything inside it, as opted out of routing. No file inside a private folder, no matter what it's named, will ever become a route.Folder structure
app/
dashboard/
_components/
Chart.tsx
StatCard.tsx
_lib/
formatCurrency.ts
page.tsx // route: /dashboard
settings/
page.tsx // route: /dashboard/settings_components/ and _lib/ live right next to the routes that use them, but neither folder — nor anything inside it — is reachable as a URL. Even if someone added a _components/page.tsx by mistake, it would still not become a route.Why not just colocate directly?
page.tsx in the same folder — this general colocation philosophy is covered on the Project Structure page. Only files with specific reserved names (page.tsx, layout.tsx, loading.tsx, route.ts, and a handful of others) are treated specially by the router; anything else you drop into a route folder is simply ignored by routing and can be imported like any other module.So why reach for an underscore folder at all? Two situations make it genuinely useful:
Naming collision safety — if you ever wanted a helper file literally named
pageorlayoutfor non-routing reasons, only a private folder guarantees Next.js will never treat it as a route file.Visual and structural grouping — bundling a large batch of related helpers, tests, and components under one clearly-labeled
_folderkeeps a busy route directory readable, rather than scattering many loose files next topage.tsx.Future-proofing — if Next.js ever reserves a new special filename that happens to match one of your existing colocated files, a private folder is immune to that because the entire folder is excluded from routing, not just specific filenames.
page.tsx. Once a route accumulates several supporting files — components, hooks, tests, constants — move them into an underscore-prefixed folder so the route directory stays easy to scan.