Getting Started with Next.js App Router
A practical guide to building modern web applications with Next.js App Router, Server Components, and the latest React patterns.
Why Next.js App Router?
The App Router introduced in Next.js 13 represents a fundamental shift in how we build React applications. Instead of the traditional pages directory, we now have a file-system based router built on top of React Server Components.
Key advantages include:
- Server Components by default — less JavaScript shipped to the client
- Nested layouts that persist across navigations
- Streaming with loading UI and Suspense boundaries
- Built-in data fetching without useEffect or external libraries
Project Setup
Getting started is straightforward:
npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app
npm run devThis scaffolds a project with TypeScript, Tailwind CSS, and the App Router enabled out of the box.
Understanding the File Conventions
The App Router uses special file names to define UI:
| File | Purpose |
|---|---|
layout.tsx | Shared UI that wraps child routes |
page.tsx | Unique UI for a route |
loading.tsx | Loading state with Suspense |
error.tsx | Error boundary for a segment |
not-found.tsx | 404 UI for a segment |
Server vs Client Components
By default, every component in the App Router is a Server Component. This means it runs on the server and sends only HTML to the browser.
When you need interactivity, add the "use client" directive:
"use client";
import { useState } from "react";
export function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}Rule of thumb: Keep components on the server unless they need browser APIs, event handlers, or React state.
Data Fetching
One of the biggest improvements is how data fetching works. Server Components can be async:
async function BlogPosts() {
const posts = await db.post.findMany({
orderBy: { createdAt: "desc" },
});
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}No useEffect. No loading state management. No client-side fetching library. The data is fetched on the server and streamed to the client as HTML.
Dynamic Routes
Dynamic segments use bracket notation in folder names:
app/blog/[slug]/page.tsx
Combined with generateStaticParams, you get static generation for known paths:
export function generateStaticParams() {
return [
{ slug: "hello-world" },
{ slug: "getting-started" },
];
}Conclusion
The App Router is a major step forward for React development. Server Components reduce bundle sizes, nested layouts eliminate redundant re-renders, and the file-based conventions make routing intuitive. If you're starting a new project today, the App Router is the way to go.