App Router vs Pages Router: which one should you build on in 2026?
The two Next.js routers are not two syntaxes for the same thing. They are different rendering models, and that difference decides your data fetching, caching and hiring plan.
React Server Components render exclusively on the server and send a serialised description of the UI to the browser instead of component JavaScript. They can await data directly, cannot use state or effects, and reduce client bundle size because their code never reaches the browser.
A React Server Component is a component that runs only during rendering on the server and never ships its source code to the browser.
Rather than sending your component code plus data to the browser and rendering there, the server executes the component and streams a compact description of the resulting UI tree — the RSC payload — to React on the client. React uses that description to build the DOM and to reconcile with any client components in the tree.
The practical consequence: a server component can import a 300 KB markdown parser, a date library and your database client, and the browser downloads none of it. That is the entire point.
| Capability | Server component | Client component |
|---|---|---|
| Async / await in the body | Yes | No |
| useState, useEffect | No | Yes |
| Event handlers (onClick) | No | Yes |
| Direct database or filesystem access | Yes | No |
| Ships JavaScript to browser | No | Yes |
| Access to browser APIs | No | Yes |
"use client" at the top of a file marks an entry point into the client bundle. Every module that file imports — and everything those modules import — is compiled for the browser too. This is the single most misunderstood detail of the model.
The failure mode we see most often: a team puts "use client" in the root layout to make a theme provider work, and the entire application silently becomes a client application again. The App Router is still used, the performance benefit is gone.
// Wrong: the whole tree becomes client code
"use client";
export default function Layout({ children }) {
return <ThemeProvider>{children}</ThemeProvider>;
}
// Right: only the provider is a client component
import { ThemeProvider } from "./theme-provider"; // "use client" lives there
export default function Layout({ children }) {
return <ThemeProvider>{children}</ThemeProvider>;
}The rule we apply on every project: the client boundary belongs at the smallest interactive unit, not at the page or layout. A product page is a server component; the add-to-cart button inside it is a client component. A dashboard is a server component; the chart with a hover tooltip is a client component.
Highly interactive surfaces — a canvas editor, a spreadsheet, a real-time collaborative document — are client applications with a server behind them. Forcing them into a server-first structure adds ceremony without benefit. Use server components for the shell, authentication and initial data, and let the interactive core be a client island.
Similarly, if your data changes on every keystroke, the round trip to a server component is worse than a client fetch. Server components optimise for content that is stable within a request, not for per-interaction updates.
No. SSR renders your components to HTML on the server but still ships the component JavaScript to the browser for hydration. Server components never ship that JavaScript at all. Most App Router apps use both together.
Yes, and that is the normal direction. A client component cannot import a server component directly, but it can receive one as children or as a prop.
They require a bundler and framework integration. Next.js and a small number of other frameworks implement the protocol; you cannot drop them into a plain Vite React app today.
Run a bundle analyser against your production build and look at the first-load JavaScript per route. Any unexpected library in there almost always traces back to a "use client" file importing it.
Harshal Patel
Founder & Lead Engineer, ROVQIX
Harshal leads engineering at ROVQIX, where he has shipped production Next.js, Node.js and PostgreSQL systems for startups, SaaS teams and ecommerce brands. He writes about the trade-offs behind architecture decisions rather than the framework of the week.
ROVQIXdesigns and builds production web platforms — Next.js front ends, Node.js APIs and the infrastructure behind them. Tell us what you're building and we'll scope it with you.
The two Next.js routers are not two syntaxes for the same thing. They are different rendering models, and that difference decides your data fetching, caching and hiring plan.
A server action is a public HTTP endpoint with nicer syntax. Treat it like one and they are excellent; forget that and you have shipped an unauthenticated API.
Sprinkling memo and useCallback across a codebase is not optimisation, it is superstition. Measure first, then apply one of four structural fixes.
No spam. Just the occasional case study and craft breakdown.