In the App Router, folders define the URL structure, but special files define the UI behavior. This convention over configuration approach allows Next.js to handle complex React features like Suspense and Error Boundaries automatically.
Each folder in our app directory represents a route segment. Within these segments, Next.js looks for specific filenames to build the component tree.
page.tsxThis is the only file that makes a route publicly accessible. It defines the unique UI for that specific path.
layout.tsxUsed to share UI across multiple pages (e.g., Navbar, Sidebar).
template.tsxSimilar to layouts, but with one key difference: Templates create a new instance for each child on navigation.
useEffect hooks that must run every time we switch pages.layout.tsx by default; only use template.tsx if you specifically need the "mount/unmount" behavior.loading.tsxNext.js uses this file to create an automatic React Suspense boundary around our page.tsx.
loading.tsx UI (like a skeleton screen) instead of a blank page.error.tsx & not-found.tsxerror.tsx: An Error Boundary that catches runtime exceptions in its segment. It must be a Client Component because it needs to provide a Try Again button.not-found.tsx: Triggered when the notFound() function is called or when a route doesn't exist.When we visit a URL, Next.js assembles the components in a specific order. Imagine the folder structure: /dashboard/settings. The hierarchy looks like this:
layout.tsx (Root)layout.tsx (Dashboard)error.tsx (Dashboard)loading.tsx (Dashboard)page.tsx (Settings)Key Rule: A layout in a parent folder wraps the layouts and pages in its child folders.
The beauty of
loading.tsxanderror.tsxis that they allow us to handle 'unhappy paths' declaratively. We don't needif (loading)ortry/catchlogic inside our components; the file system handles the switching for us.
| File | Purpose | Re-renders on Nav? | Component Type |
|---|---|---|---|
page.tsx | Unique Route UI | Yes | Server/Client |
layout.tsx | Shared/Persistent UI | No | Server (Default) |
template.tsx | Shared UI (Resetting) | Yes | Server/Client |
loading.tsx | Suspense Fallback | N/A | Server/Client |
error.tsx | Error Recovery | N/A | Client Only |
Next.js provides specialized folder patterns that allow us to manipulate the URL structure and organize code without cluttering the browser's address bar.
Sometimes we want to group routes together (e.g., all Auth pages or all Dashboard pages) but we don't want the folder name to appear in the URL.
(auth).app/(auth)/login/page.tsx becomes your-domain.com/login.(auth) can share a layout with no navbar, while pages in (marketing) share a layout with a big hero section.By default, every folder in app is a potential route segment. If we want to keep your components, hooks inside the route folder but prevent them from being accessible via a URL, use an underscore.
_components.page.tsx without accidentally creating a /components URL.When we don't know the exact segment name ahead of time (e.g., a blog post ID or a username), we use dynamic segments.
[id].page.tsx via the params prop.// app/blog/[slug]/page.tsx
export default function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const data = await params;
return <h1>Reading: {data.slug}</h1>;
}If you need to match multiple levels of a URL (e.g., a documentation site with infinite nested categories), use the spread operator.
[...slug] (matches /docs/setup, /docs/setup/linux, etc.)[[...slug]] (also matches the root /docs without extra segments).| Pattern | Folder Syntax | URL Impact | Best For |
|---|---|---|---|
| Standard Route | dashboard | /dashboard | Regular pages. |
| Route Group | (marketing) | None | Shared layouts without URL bloat. |
| Private Folder | _lib | Hidden | Colocating code, components, or styles. |
| Dynamic Route | [id] | /123 | Dynamic content like IDs or slugs. |
| Catch-all | [...slug] | /a/b/c | Complex docs or folder navigations. |
Route Groups are our best friend for cleaner architecture. Instead of having a messy root
appfolder, group features into(main),(auth), and(admin). This keeps our layouts organized and your URL structure exactly how we want it.