Next.js App Router - Complete Guide to Modern Routing
Mahesh Waghmare Next.js App Router (introduced in Next.js 13) revolutionizes how we build React applications with file-based routing, server components, and advanced data fetching patterns.
Introduction to App Router
The App Router uses React Server Components and provides a new routing system based on the app directory structure.
Key Features:
- File-based routing
- Server Components by default
- Built-in layouts
- Loading states
- Error boundaries
- Streaming and Suspense
Benefits:
- Better performance
- Improved developer experience
- Automatic code splitting
- Built-in optimizations
File-Based Routing
Basic Routes
app/
├── page.js # / (homepage)
├── about/
│ └── page.js # /about
├── blog/
│ └── page.js # /blog
└── contact/
└── page.js # /contact
Dynamic Routes
app/
├── blog/
│ └── [slug]/
│ └── page.js # /blog/[slug]
└── users/
└── [id]/
└── page.js # /users/[id]
Catch-All Routes
app/
└── docs/
└── [...slug]/
└── page.js # /docs/* (catches all paths)
Route Groups
app/
├── (marketing)/
│ ├── about/
│ └── contact/
└── (shop)/
├── products/
└── cart/
Layouts and Nested Routes
Root Layout
// app/layout.js
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<header>Navigation</header>
{children}
<footer>Footer</footer>
</body>
</html>
);
}
Nested Layouts
// app/dashboard/layout.js
export default function DashboardLayout({ children }) {
return (
<div>
<aside>Dashboard Sidebar</aside>
<main>{children}</main>
</div>
);
}
Layout Benefits
- Shared UI across routes
- Preserve state during navigation
- Nested layouts
- Multiple layouts per route
Loading and Error States
Loading UI
// app/dashboard/loading.js
export default function Loading() {
return <div>Loading dashboard...</div>;
}
Error Boundaries
// app/dashboard/error.js
'use client';
export default function Error({ error, reset }) {
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={() => reset()}>Try again</button>
</div>
);
}
Not Found Pages
// app/dashboard/not-found.js
export default function NotFound() {
return <h1>Dashboard page not found</h1>;
}
Server Components
Data Fetching
// app/posts/page.js
async function PostsPage() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return (
<div>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
</article>
))}
</div>
);
}
Server Actions
// app/actions.js
'use server';
export async function createPost(formData) {
const title = formData.get('title');
// Save to database
return { success: true };
}
Advanced Routing Patterns
Parallel Routes
app/
└── dashboard/
├── @analytics/
│ └── page.js
├── @team/
│ └── page.js
└── page.js
Intercepting Routes
app/
├── @modal/
│ └── (.)photos/
│ └── [id]/
│ └── page.js
└── photos/
└── [id]/
└── page.js
Conclusion
Next.js App Router provides:
- Modern routing system
- Server Components
- Built-in optimizations
- Better developer experience
Key principles:
- Use file-based routing
- Leverage layouts
- Handle loading and errors
- Use Server Components for data
- Implement proper error boundaries
Mastering App Router is essential for modern Next.js development.
Written by Mahesh Waghmare
I bridge the gap between WordPress architecture and modern React frontends. Currently building tools for the AI era.
Follow on Twitter →