This is a reference-style guide to the core conventions of the Next.js App Router.
File conventions
| File | Purpose |
|---|---|
layout.tsx | Shared UI that wraps a segment and its children |
page.tsx | The unique UI for a route, making it publicly accessible |
loading.tsx | Loading UI shown while a segment loads |
not-found.tsx | UI rendered when notFound() is called |
error.tsx | Error boundary for a segment |
route.ts | An API endpoint (Route Handler) for a segment |
Nested layouts
Layouts nest automatically based on folder structure. A layout.tsx in app/blog/ wraps every route under /blog, in addition to the root layout.
app/
layout.tsx → wraps everything
blog/
layout.tsx → wraps everything under /blog
page.tsx → /blog
[slug]/
page.tsx → /blog/[slug]
Static params for dynamic routes
For a fully static export, every dynamic segment needs generateStaticParams so Next.js knows every path to pre-render at build time.
export async function generateStaticParams() {
const posts = getAllPosts();
return posts.map((post) => ({ slug: post.slug }));
}Metadata
Each route can export a generateMetadata function to produce per-page <title>, description, and Open Graph tags at build time.
export async function generateMetadata({ params }) {
const { slug } = await params;
const post = getPostBySlug(slug);
return { title: post.title, description: post.description };
}Server vs. Client Components
By default, every component in app/ is a Server Component. Add "use client" at the top of a file only when you need interactivity, browser APIs, or React hooks like useState.
Route groups and parallel routes
Two less obvious file conventions worth knowing once the basics above feel routine:
app/
(marketing)/
layout.tsx → its own layout, applies to pages inside
page.tsx → still just "/", the parens don't affect the URL
(app)/
dashboard/
page.tsx → "/dashboard"
Parentheses around a folder name ((marketing)) create a route group — it organizes routes and can carry its own layout without adding a segment to the actual URL. This is the tool for giving a marketing site section and an authenticated app section entirely different layouts while both living under the same app/ tree.
app/
@modal/
(.)photo/[id]/page.tsx → intercepted route, rendered as a modal
photo/[id]/
page.tsx → the full page, for a direct visit/refresh
Parallel and intercepting routes (the @modal and (.) conventions) let a route render as a modal overlay when navigated to from within the app, while still rendering as a full standalone page on a direct URL visit or refresh — the pattern behind "click a photo thumbnail, it opens as a modal, but the modal's URL is also a real, shareable, fully-rendered page."
Loading and error boundaries are scoped per segment
loading.tsx and error.tsx aren't global — each one only wraps the segment (and its children) where it's placed, which means different parts of a route tree can have independent loading and error states instead of one blanket spinner or error page for the whole app:
app/
dashboard/
loading.tsx → shown while anything under /dashboard is loading
error.tsx → catches errors from /dashboard and its children only
settings/
loading.tsx → overrides the parent's, just for /dashboard/settings
A nested loading.tsx takes priority over a parent's for its own subtree, letting a slow-loading nested section show its own loading state without blanking out the rest of an already-rendered page around it.
Colocating non-route files safely
Any file inside app/ that isn't one of the special names above (_components/, _utils/, or a leading-underscore folder) is safe to colocate next to the routes that use it, without becoming a route itself:
app/
blog/
_components/
PostCard.tsx → not a route, safe to colocate here
page.tsx
[slug]/
page.tsx
The underscore prefix explicitly opts a folder out of routing, which is the cleanest way to keep a route's helper components physically close to where they're used instead of pushed into a distant shared components/ directory purely to avoid accidentally creating a route.
Common mistakes
- Adding
"use client"to a component "just in case." Every Client Component adds JavaScript to the bundle sent to the browser — reserve it for components that genuinely need interactivity, and keep data-fetching and static markup as Server Components. - Calling a browser-only API (
window,localStorage,document) directly during render in a Client Component. It runs during the server-render pass too (Client Components are still rendered on the server for the initial HTML) — guard with a mount check or move the read into auseEffect. - Forgetting
generateStaticParamson a dynamic route ([slug]) when building withoutput: "export". Static export has no server to render a route on demand — every dynamic segment must be pre-rendered at build time, or the build fails outright rather than falling back gracefully. - Fetching data in a Client Component with
useEffectwhen the same data could be fetched in a parent Server Component and passed down as a prop — this needlessly moves the fetch to the browser, adding a loading state and a network waterfall that server-side fetching avoids entirely.
Troubleshooting
- Hydration mismatch warnings — check for any value that can differ between server and client renders: dates formatted with the visitor's local timezone, random IDs generated without a stable seed, or conditional rendering based on
typeof window. - "Error: Dynamic server usage" during a static export build — a Server Component is calling something that requires per-request data (reading cookies, headers, or search params) that static export can't resolve at build time. Either remove the dependency or handle that logic client-side.
- A route renders correctly in
next devbut 404s afternext buildwith static export — confirmgenerateStaticParamsactually returns that specific path; dev mode renders dynamic routes on demand, but static export only ships what was explicitly pre-rendered.
Related reading
- Next.js Middleware: What It's For and When to Avoid It — shares tags: nextjs, react, web-development (same category).
- React Server Components Explained: What They Are and When to Use Them — shares tags: react, nextjs, web-development.
- React useEffect Cleanup: A Practical Guide — shares tags: react, web-development.
- Core Web Vitals Explained: What Actually Affects Your Score — shares tags: web-development.
- The JavaScript Event Loop, Explained With Diagrams — shares tags: web-development.