Next.js App Router Overview
app/ directory mental model — layouts, server components by default, routing conventions, and how App Router differs from Pages Router.
- nextjs
- app-router
- routing
- rsc
The App Router (app/) is Next.js’s modern routing and rendering model. It is built around React Server Components (RSC), nested layouts, and file-system conventions for loading/error UI, routes, and metadata. The older Pages Router (pages/) still works; new features and docs center on App Router.
Docs: Next.js App Router, Routing, React Server Components.
Mental model in one screen
app/
layout.tsx ← root layout (html/body), wraps all routes
page.tsx ← UI for /
loading.tsx ← Suspense fallback for the segment
error.tsx ← error boundary for the segment
not-found.tsx
blog/
layout.tsx ← nested layout, wraps /blog/*
page.tsx ← /blog
[slug]/
page.tsx ← /blog/:slug
api/
hello/
route.ts ← Route Handler (HTTP endpoint)
- Folders define URL segments.
- Special files define UI and behavior for that segment.
- Layouts persist across navigations of their children (state/UI chrome can remain mounted).
- Default components are Server Components — no
"use client"unless you need browser APIs, state, or effects.
App Router vs Pages Router
| App Router | Pages Router | |
|---|---|---|
| Directory | app/ |
pages/ |
| Components default | Server Components | Client (classic React) |
| Layouts | Nested layout.tsx |
_app + limited patterns |
| Data fetching | async Server Components, fetch cache model, Server Actions |
getServerSideProps / getStaticProps |
| Routing extras | Intercepting, parallel routes, route groups | Conventional file routes |
| API | route.ts handlers |
pages/api/* |
You can migrate incrementally; both trees can coexist. Don’t mix mental models inside one feature without knowing where the boundary is.
Core file conventions
| File | Role |
|---|---|
layout.tsx |
Shared UI shell; receives children |
page.tsx |
The leaf UI that makes a route publicly accessible |
loading.tsx |
Instant loading UI via Suspense |
error.tsx |
Client error boundary for the segment |
template.tsx |
Like layout but remounts on navigation |
default.tsx |
Fallback for parallel routes |
route.ts |
HTTP handler (GET/POST/…) |
middleware.ts |
Edge middleware (project root / src) |
A route is not complete without a page.js/ts (or a route handler for APIs). Layouts alone don’t create a URL.
Route groups and organization
app/
(marketing)/
page.tsx → /
about/page.tsx → /about
(shop)/
layout.tsx
cart/page.tsx → /cart
Parentheses (group) organize code without affecting the URL. Use them for different root layouts (marketing vs app chrome) or team boundaries.
Dynamic segments
app/blog/[slug]/page.tsx
app/shop/[category]/[item]/page.tsx
app/docs/[...slug]/page.tsx # catch-all
app/docs/[[...slug]]/page.tsx # optional catch-all
// app/blog/[slug]/page.tsx
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getPost(slug);
return <article>…</article>;
}
(Next.js versions tightened params / searchParams toward async — check your version’s docs and type helpers.)
Server Components by default
// app/users/page.tsx — Server Component
import { db } from '@/lib/db';
export default async function UsersPage() {
const users = await db.user.findMany();
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
Benefits aimed at real product metrics:
- Less client JS for data-heavy pages → better INP and parse/hydrate cost.
- Secrets and DB stay on the server.
- Streaming with Suspense for progressive HTML (critical path / LCP when done well).
When you need state, effects, or browser-only APIs:
'use client';
import { useState } from 'react';
export function Counter() {
const [n, setN] = useState(0);
return <button type="button" onClick={() => setN(n + 1)}>{n}</button>;
}
Push "use client" to the leaves. A client parent forces its imports into the client bundle boundary. Deep dive: Server Components in Next.js.
Navigation and linking
import Link from 'next/link';
<Link href="/blog/hello">Hello</Link>
Prefer Link / next/navigation over raw <a> for internal routes so client transitions and prefetch work. Still: links navigate, buttons act — links vs buttons.
Prefetching is on for static routes in viewport by default — know that for analytics and bursty dashboards.
Data and caching (high level)
App Router fetch integrates with Next’s cache/revalidate model:
const res = await fetch('https://api.example.com/item', {
next: { revalidate: 60, tags: ['item'] },
});
Mental buckets: static vs dynamic rendering, revalidatePath / revalidateTag, and when cookies/headers force dynamic. Treat this as its own topic — overview stop: caching is opt-in complexity; measure TTFB and LCP when you change it.
Metadata
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Blog',
description: 'Posts from the team',
};
Or generateMetadata for dynamic SEO. Replaces many next/head patterns from Pages Router.
Security and boundaries
- Server Components can import server-only modules; don’t leak secrets into client components via props that serialize to the client.
- Server Actions need authz checks — they are public endpoints.
- CSP nonces integrate at the document layer — see Content Security Policy.
- User HTML still XSS — XSS guide.
Common pitfalls
- Marking entire trees
"use client"“to make hooks work” — push the boundary down. - Fetching in client components what a Server Component could load cheaper.
- Forgetting root
layout.tsxmust include<html>and<body>. - Expecting layout state to reset on every navigation — use
templateif you need remounts. - Mixing
pages/data APIs insideapp/files. - Over-prefetching authenticated pages with sensitive data assumptions.
Interview angle
Explain nested layouts + Server Components default. Contrast App vs Pages data fetching. Show when "use client" is required. Mention loading.tsx as segment Suspense and impact on UX/streaming.
One-liner:
“App Router is file-system routes with nested layouts and RSC by default; client components are opt-in leaves.”
Related on this site
- Server Components in Next.js
- Core Web Vitals
- Critical rendering path
- LCP optimization tactics
- Links vs buttons
- Content Security Policy
Further reading
- Next.js: App Router docs
- Next.js: Project structure
- Next.js: Linking and navigating
- Next.js: Caching
- React: Server Components
Related guides
- Server Components in Next.jsRSC mental model in the App Router — server vs client boundaries, data fetching, serialization rules, and composition patterns that stay maintainable.
- Auth Patterns OverviewAuth in Next.js App Router: cookies/sessions, middleware gates, server checks, and avoiding client-only security theater.
- Caching in Next.js OverviewNext.js caching layers: request memoization, data cache, full route cache, and router cache — what invalidates each.
- Client Components in Next.jsClient Components in the App Router: use client, hydration, bundling boundaries, and patterns that keep JS small.
- Data Fetching Patterns App RouterFetch data in Server Components with async/await and fetch caching: colocation, parallel requests, and client fallbacks.