As an application grows, the app/ folder starts to fight you: marketing pages want a different shell from the logged-in area, helper components end up next to routes, and URLs mirror folder names whether you like it or not. Route groups, private folders and the src/ directory solve these problems. After this lesson you will be able to organise a large App Router project so that folder structure serves the team without leaking into URLs.
Wrap a folder name in parentheses and Next.js omits it from the path:
app/
├── (marketing)/
│ ├── layout.tsx # marketing layout
│ ├── page.tsx # /
│ └── pricing/page.tsx # /pricing
└── (app)/
├── layout.tsx # application layout
└── dashboard/page.tsx # /dashboard/pricing and /dashboard are served as if the groups did not exist, yet each group has its own layout.tsx. This is the standard way to give sections of a site different navigation, sidebars or metadata without adding a URL prefix. Groups can also be used purely for tidiness, for example (shop) and (account), with no layout at all.
Two rules to remember:
(marketing)/about/page.tsx and (app)/about/page.tsx both map to /about and the build fails.If you delete the top-level app/layout.tsx and give every route group its own layout containing <html> and <body>, each group becomes an independent application shell. This is useful when a documentation site and a web app share one deployment but nothing else:
// app/(docs)/layout.tsx
export default function DocsLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className="docs-theme">{children}</body>
</html>
);
}The page for / must then live inside one of the groups, for example app/(marketing)/page.tsx.
Only page.tsx and route.ts make a folder publicly reachable, so you can safely keep components, tests and utilities next to the routes that use them. To make the intent explicit, prefix a folder with an underscore:
app/
├── dashboard/
│ ├── _components/Chart.tsx # not a route
│ ├── _lib/queries.ts # not a route
│ └── page.tsx # /dashboardA private folder and everything inside it is excluded from routing entirely. It also keeps generated route types clean. If you ever need a real URL segment that starts with an underscore, use the encoded form %5Ffolder.
Many teams move app/ into src/ so configuration files stay at the project root while application code (src/app, src/components, src/lib, src/hooks) sits together. create-next-app offers this layout as a prompt and configures an import alias:
{
"compilerOptions": {
"paths": { "@/*": ["./src/*"] }
}
}With the alias, any file imports shared code as import { db } from "@/lib/db" regardless of how deep it lives. public/, next.config.ts and package.json always stay at the root.
| Convention | Effect on URL | Typical use |
|---|---|---|
| (group) | Removed from the path | Separate layouts, logical sections |
| _folder | Never routable | Colocated components and helpers |
| [param] | Dynamic segment | Details pages |
| src/app | None | Keeps root directory tidy |
(auth), (marketing), (dashboard).layout.tsx for truly global concerns (fonts, providers, analytics) and push everything else into group layouts.What URL does `app/(shop)/cart/page.tsx` serve?
(name) organise routes and attach layouts without changing URLs.app/layout.tsx and giving each group its own <html> layout creates multiple root layouts._name are never routable, making colocation of components safe and explicit.src/ directory separates application code from root configuration files.Next lesson: Linking and Navigation — use the Link component for fast client-side transitions and prefetching.