The Next.js App Router, introduced in version 13 and refined in 14 and 15, has fundamentally changed how we build React applications. It brings Server Components, nested layouts, and simplified data fetching—making apps faster and more maintainable. I recently migrated a production app from Pages Router to App Router, and while there was a learning curve, the benefits were immediate. This guide walks through the essentials, with practical tips for making the transition smooth.
- Understanding the App Router
- File-Based Routing Conventions
-
Server Components vs Client Components
- When to Use Each
- The "use client" Directive
- Composing Components
- Data Fetching Patterns
- Layouts and Templates
- Migrating from Pages Router
1. Understanding the App Router
The App Router lives in the app/ directory and uses React Server Components by default. Unlike the old Pages Router, components render on the server unless you explicitly opt into client-side behavior. This means faster initial loads and better SEO without extra configuration.
The mental shift is simple: assume everything runs on the server, then selectively add client interactivity where needed.
2. File-Based Routing Conventions
Routing in the App Router uses special file names:
- page.tsx: Defines a route's UI.
app/about/page.tsxcreates/about. - layout.tsx: Wraps child routes with shared UI like nav bars.
- loading.tsx: Automatic loading state while data fetches.
- error.tsx: Error boundaries for graceful failures.
- route.ts: API routes (like
/api/users).
Folders define routes, and these special files control behavior. It's intuitive once you see it in action.
app/
layout.tsx # Root layout
page.tsx # Home page
about/
page.tsx # /about
blog/
[slug]/
page.tsx # /blog/:slug
3. Server Components vs Client Components
3.1 When to Use Each
Server Components (default) are for static content, data fetching, and SEO-critical pages. They can directly query databases without exposing APIs.
Client Components handle interactivity like forms, onClick handlers, and React hooks (useState, useEffect). Mark them with 'use client' at the top of the file.
3.2 The "use client" Directive
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return ;
}
This tells Next.js to bundle this component for the browser.
3.3 Composing Components
You can nest Client Components inside Server Components, but not the other way around. Structure your app to maximize server rendering for performance.
4. Data Fetching Patterns
Server Components can use async/await directly in the component:
export default async function BlogPost({ params }) {
const post = await fetch(`https://api.example.com/posts/${params.slug}`)
.then(res => res.json());
return {post.content} ;
}
Next.js automatically caches fetch requests and revalidates on-demand or at intervals. Use revalidate for ISR:
fetch(url, { next: { revalidate: 60 } })
For client-side fetching, use SWR or React Query as usual.
5. Layouts and Templates
Layouts wrap multiple pages and persist across navigations. Great for headers and sidebars:
export default function RootLayout({ children }) {
return (
{children}
);
}
Nested layouts let you add section-specific wrappers. Templates are like layouts but re-mount on navigation—useful for animations.
6. Migrating from Pages Router
Start by moving static pages first. The Pages Router still works, so you can migrate incrementally. Key differences:
- No getServerSideProps—use async Server Components.
- No getStaticProps—fetch directly in components.
- Move
_app.tsxlogic toapp/layout.tsx. - API routes stay similar but move to
app/api/.
The official Next.js migration guide is detailed—follow it step by step.
The App Router is Next.js at its best—faster, simpler, and more powerful. It takes time to adjust from the Pages Router, but the payoff in performance and developer experience is worth it. Building your first App Router project? Share your experience below!
Post a Comment