Section 01 · The tour
What every file in a fresh Next.js app does
If you just ran create-next-app and opened the folder in your editor, this is the map.
Quick answer
What is the Next.js folder structure? A Next.js project is built around the app folder. Folders inside app/ become URL routes. Each route has a page.tsx (the visible page) and optionally a layout.tsx (wraps the page with shared UI), loading.tsx (shown while data loads), and error.tsx (shown if something throws). Static files live in public/. Config files like next.config.js sit at the root.
Open the project you generated in the previous post. You will see a tree that looks roughly like this:
my-first-app/
├── app/ ← your pages and layouts live here
│ ├── favicon.ico
│ ├── globals.css ← Tailwind directives + global styles
│ ├── layout.tsx ← root layout (wraps every page)
│ └── page.tsx ← the home page at /
├── public/ ← static assets served as is
│ ├── next.svg
│ └── vercel.svg
├── node_modules/ ← installed packages (do not edit)
├── .gitignore
├── eslint.config.mjs
├── next.config.ts ← Next.js configuration
├── next-env.d.ts ← auto generated, do not edit
├── package.json ← dependencies and scripts
├── postcss.config.mjs ← required by Tailwind
├── README.md
├── tailwind.config.ts
└── tsconfig.json ← TypeScript configSection 02 · The app folder
The app folder is where you spend ninety percent of your time
Every page, every layout, every loading state, every error boundary lives here. The folder structure is the routing system.
The rule is short. A folder inside app/ becomes a URL segment. A file named page.tsx inside that folder makes the URL render a page. That is it.
app/page.tsx → /
app/about/page.tsx → /about
app/blog/page.tsx → /blog
app/blog/[slug]/page.tsx → /blog/anything-here
app/dashboard/settings/page.tsx → /dashboard/settingsThe square brackets around [slug] mark a dynamic segment. Anything the user types in that part of the URL is passed to your page component as a prop. That is how you build blog posts, product pages, user profiles, and anything else with a variable URL.
No route configuration file
Other frameworks (React Router, plain Express, even old Next.js with the Pages Router) make you write a routes table. App Router throws that away. The folder structure IS the routes table. Rename a folder and you rename the URL.
Section 03 · Special files
The reserved file names you need to know
Next.js looks for files with specific names inside every route folder. These are the ones worth memorising.
| File name | What it does | When you write it |
|---|---|---|
| page.tsx | Makes the folder a visitable URL. Renders the page body. | Every route you want users to visit. |
| layout.tsx | Wraps every page in this folder (and child folders) with shared UI: header, footer, nav. | Once per section that shares chrome. |
| loading.tsx | Shown automatically while the page is fetching data on the server. | Any route with slow data. |
| error.tsx | Catches uncaught errors thrown by the page and shows a fallback UI. | Production apps with real users. |
| not-found.tsx | Renders when a dynamic route cannot find the requested resource. | Dynamic routes like blog posts or product pages. |
| template.tsx | Like layout, but a fresh instance is created on every navigation. | Rarely. Use layout unless you need this. |
| route.ts | Defines an HTTP endpoint instead of a page. Returns JSON, not JSX. | API routes. |
The most important pair is layout.tsx and page.tsx. Every Next.js app has a root layout at app/layout.tsx that wraps every page. It is also where you set the <html> and <body> tags. You cannot remove it.
// app/layout.tsx — wraps every page in the app
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<nav>{/* shared nav */}</nav>
{children}
<footer>{/* shared footer */}</footer>
</body>
</html>
);
}Section 04 · Server vs Client
Server Components vs Client Components, in plain English
This is the one Next.js concept that trips up everyone. Get it right once and you never have to think about it again.
Every component inside the app/ folder is a Server Component by default. That means it runs on the server, fetches data directly, and ships zero JavaScript to the browser.
// app/page.tsx — a Server Component (default)
export default async function HomePage() {
// This fetch runs on the server, not the browser.
const posts = await fetch("https://api.example.com/posts").then((r) => r.json());
return (
<main>
{posts.map((p: any) => (
<article key={p.id}>{p.title}</article>
))}
</main>
);
}A Server Component cannot use useState, useEffect, browser APIs, or onClick. The moment you need any of those, you need a Client Component. You make one by writing the string "use client" as the very first line of the file:
"use client";
import { useState } from "react";
// app/components/counter.tsx — a Client Component
export function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}A simple rule that works
Default to Server Components. Only add 'use client' when you need state, an event handler, or a browser only API. The Server Component can still render a Client Component inside it; the boundary just needs to be clear.
Section 05 · public folder
The public folder: where images and static files live
Anything in here is served as a static file at the root of your site.
Drop an image at public/logo.png and it is reachable at /logo.png in the browser. You do not import it; you reference the URL directly:
import Image from "next/image";
export default function Header() {
return (
<Image src="/logo.png" alt="Company logo" width={120} height={40} />
);
}The <Image> component is the recommended way to use images. It handles lazy loading, responsive sizing, and modern formats (AVIF, WebP) for you. For SVG and favicons, a plain <img> tag is fine.
Section 06 · Config
The config files at the root, briefly
You do not need to touch most of these on day one. Knowing what each is for stops them from being intimidating later.
| File | Purpose | Edit often? |
|---|---|---|
| package.json | Lists your dependencies and scripts (dev, build, start, lint). | Yes, every time you add a library. |
| next.config.ts | Next.js configuration. Image domains, redirects, custom Webpack, env, experimental flags. | Sometimes. |
| tsconfig.json | TypeScript compiler config. Path aliases, strictness, target. | Rarely. |
| tailwind.config.ts | Tailwind theme, plugins, content paths. | When you customise the design system. |
| eslint.config.mjs | ESLint rules and plugins. | Almost never on day one. |
| postcss.config.mjs | Required so Tailwind's PostCSS plugin runs at build time. | No. |
| .gitignore | Files Git should not track (node_modules, .next, .env). | When you add new build artefacts. |
| next-env.d.ts | Auto generated TypeScript references for Next.js types. | Never. It is regenerated. |
Section 07 · Route grouping
Two patterns you will use as the app grows
Route groups and private folders are the two App Router conventions worth learning before you build a second page.
Route groups: folder names in (parentheses)
A folder wrapped in parentheses is not part of the URL. Use this to group related routes that share a layout without affecting the path. app/(marketing)/about/page.tsx still renders at /about, but you can give the (marketing) folder its own layout.tsx that wraps every marketing page.
Private folders: names starting with _
A folder whose name starts with an underscore is invisible to the router. Use it for component files that should live near a route but should not become a URL. app/dashboard/_components/chart.tsx is a perfect home for a chart used only on the dashboard.
You will pick up dynamic routes ([slug]), catch all routes ([...slug]), parallel routes (@modal), and intercepting routes when you need them. You do not need them on day one. The patterns above cover the first ten or twenty pages of almost any project.
Section 08 · Next steps
What to build first
The fastest way to lock in this mental model is to build something tiny.
Open the next post in this series, Build a Calculator in Next.js Step by Step. You will create a new route, write your first Client Component, and put the folder structure rules above to work in under an hour. After that, the form tutorial shows the same patterns applied to the most common UI in any web app.
If you are evaluating Next.js for a larger build, the agentic AI consulting service covers how production Next.js apps are scoped, including which folder patterns scale and which break the moment you have a real team.
Section 09 · Questions
Frequently asked questions
The common questions beginners ask about App Router and the project layout.
What is the difference between App Router and Pages Router?
App Router is the new system based on the app folder, with Server Components by default. Pages Router is the older system based on the pages folder, with Client Components by default. Pages Router still works but is in maintenance mode. Every new Next.js tutorial assumes App Router.
Can I have both app and pages folders in the same project?
Yes, Next.js supports both at once for migration. In practice, do not start a new project with both. Pick App Router and stay there.
Where do I put my reusable components?
Two common patterns work. Put global components in a components folder next to app at the root, like src/components/. Put route specific components inside the route folder using the _components private folder convention. Both are valid.
Why does the page show 'Hydration failed' sometimes?
It means the HTML the server rendered does not match what the client tried to render. The usual cause is using a browser API like Date.now or Math.random in a Server Component without guarding it. Move that code into a Client Component or compute it deterministically.
Do I have to use TypeScript with Next.js?
No, but you should. The whole ecosystem is typed, error messages are clearer, and refactoring is far safer. The cost of learning TypeScript on day one is small; the cost of switching to it later is huge.