The App Router & Project Structure
How folders become URLs, the special file names, and the root layout every app needs.
There's no router config file in the App Router. Instead, folders define URL segments and special files define what renders. The single most important rule:
> A folder becomes a route only when it contains a page.tsx file.
app/
page.tsx -> /
about/
page.tsx -> /about
blog/
page.tsx -> /blog
settings/
page.tsx -> /blog/settingsThe app/page.tsx file is your homepage. app/about/page.tsx is /about. The path on disk mirrors the path in the URL.
A folder inside app/ only becomes a visitable route when it contains a file named _____.tsx
The special files, each with a reserved name and job:
page.tsx— the unique UI for a route. Makes the segment publicly reachable.layout.tsx— shared UI that wraps a page and all routes nested below it. Persists across navigation (doesn't re-render).loading.tsx— instant loading UI shown while the page streams in (a Suspense fallback).error.tsx— error UI shown if the segment throws. Must be a Client Component.not-found.tsx— UI for 404s in that segment.route.ts— a backend API endpoint (covered in Module 6). A folder can havepage.tsxorroute.ts, not both.
Every other file (Button.tsx, utils.ts) is just a normal module you import — it has no routing meaning.
What is the key behavioral difference between layout.tsx and page.tsx?
- Alayout.tsx runs in the browser; page.tsx runs on the server
- BA layout wraps a page and all nested routes, and it persists (doesn't re-render) across navigation between those routes
- Cpage.tsx can fetch data but layout.tsx cannot
- DThere is no difference; they are interchangeable
Every App Router project needs one root layout at app/layout.tsx. It's the only layout that must render the <html> and <body> tags, and it receives the current page as children:
// app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang='en'>
<body>{children}</body>
</html>
);
}Whatever page the user visits is rendered into {children}. This is where you put global styles, fonts, and providers that should wrap the entire app.
Given this folder tree, which URL renders the dashboard settings page?
app/
layout.tsx
page.tsx
dashboard/
page.tsx
settings/
page.tsx- A/settings
- B/dashboard/settings
- C/dashboard/settings/page
- D/app/dashboard/settings
A realistic starter tree, so the conventions click:
app/
layout.tsx # root layout (html/body, global providers)
globals.css # global styles, imported in the root layout
page.tsx # homepage -> /
loading.tsx # fallback while any page streams
dashboard/
layout.tsx # sidebar shared by all dashboard pages
page.tsx # /dashboard
settings/
page.tsx # /dashboard/settings
api/
health/
route.ts # GET /api/health (an endpoint, not a page)
components/ # reusable components (NOT routes)
lib/ # db client, helpers (NOT routes)Notice components/ and lib/ sit outside app/ (or inside it with no page.tsx) — they're plain modules, never routes.
- Folders define URL segments, and a folder becomes a route only when it holds a
page.tsx. Thepagefilename and theapp/prefix never appear in the URL. - Special files each have a job:
layout(persistent shell),loading,error,not-found, androute.ts(an API endpoint). A folder serves apage.tsxor aroute.ts, never both. - The root
app/layout.tsxis the only layout that renders<html>and<body>, and every page flows into it aschildren.
Next up: the biggest mental shift — why your components run on the server by default.