Why the App Router
The App Router, introduced in Next.js 13, is now the default way to build Next.js applications. It uses React Server Components by default, which gives you smaller bundles, streaming, and a new mental model for data fetching.
If you're still on the Pages Router, the good news is you can migrate route by route — they can live side by side in the same project.
Folder Structure
Every folder under app/ maps to a route. The special files inside determine what renders.
page.tsx— the route's UIlayout.tsx— wraps the page and all nested routesloading.tsx— shown while the page is streamingerror.tsx— error boundarynot-found.tsx— 404 for this segment
Server Components by Default
In the App Router, every component is a Server Component unless you mark it "use client". Server Components run on the server, never ship to the browser, and can fetch data directly without useEffect.
// app/products/page.tsx — Server Component
import { getProducts } from "@/lib/db";
export default async function ProductsPage() {
const products = await getProducts();
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
);
}
When to Use Client Components
You need "use client" when you use:
- React hooks (
useState,useEffect,useReducer) - Event handlers (
onClick,onChange) - Browser-only APIs (
window,localStorage) - Third-party libraries that expect a browser environment
The rule of thumb: keep client components small and push them to the leaves of your component tree.
Data Fetching
Forget getStaticProps and getServerSideProps. In the App Router, you just await inside your Server Component.
const res = await fetch("https://api.example.com/data", {
next: { revalidate: 60 },
});
const data = await res.json();
The next option tells Next.js how to cache the result. revalidate: 60 means serve stale for up to 60 seconds. You can also pass cache: "no-store" for fully dynamic data.
Common Mistakes
- Importing server-only code into client components. If a client component imports a module that uses
fsor a database client, the build will fail. Keep them separate. - Forgetting `"use client"` on components that use hooks. The error message is helpful, but it's easy to miss at first.
- Over-using client components. If a page doesn't need interactivity, keep it a server component for speed.
Next Steps
Once you're comfortable with the basics, explore Server Actions for mutations, Route Handlers for API endpoints, and parallel routes for complex layouts. The App Router rewards learning its conventions — stick with them and your code stays consistent with the ecosystem.