Learn how to leverage the powerful features of Next.js App Router to build more efficient and maintainable React applications.
Next.js 13 introduced the App Router, a new paradigm for building React applications with server components, nested layouts, and simplified data fetching. This guide explores the key features and best practices for leveraging the App Router in your projects.
The App Router uses a file-system based router built on top of Server Components:
page.js
files define routeslayout.js
files define shared UIloading.js
files create loading stateserror.js
files handle errorsnot-found.js
files handle 404 errorsThe App Router introduces a new mental model with Server Components as the default:
// Server Component (default) export default function ServerComponent() { // This code runs on the server return <div>Server Component</div>; } // Client Component 'use client'; export default function ClientComponent() { // This code runs on the client const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }
The App Router simplifies data fetching with built-in patterns:
// app/users/page.js export default async function UsersPage() { // This fetch call is automatically deduped and cached const users = await fetch('https://api.example.com/users').then(res => res.json()); return ( <div> <h1>Users</h1> <ul> {users.map(user => ( <li key={user.id}>{user.name}</li> ))} </ul> </div> ); }
Control caching behavior with the cache
option:
// Static data (default) const data = await fetch('https://api.example.com/data'); // Dynamic data (no caching) const data = await fetch('https://api.example.com/data', { cache: 'no-store' }); // Revalidated data const data = await fetch('https://api.example.com/data', { next: { revalidate: 60 } });
Create consistent UI across routes with nested layouts:
// app/layout.js (Root layout) export default function RootLayout({ children }) { return ( <html lang="en"> <body> <header>Site Header</header> {children} <footer>Site Footer</footer> </body> </html> ); } // app/dashboard/layout.js (Nested layout) export default function DashboardLayout({ children }) { return ( <div className="dashboard-layout"> <nav>Dashboard Navigation</nav> <main>{children}</main> </div> ); }
Create API endpoints with the new Route Handlers:
// app/api/users/route.js export async function GET() { const users = await fetchUsers(); return Response.json(users); } export async function POST(request) { const data = await request.json(); const newUser = await createUser(data); return Response.json(newUser, { status: 201 }); }
Perform server-side mutations with Server Actions:
// app/actions.js 'use server'; export async function createTodo(formData) { const title = formData.get('title'); // Server-side validation if (!title || title.length < 3) { return { error: 'Title must be at least 3 characters' }; } // Create todo in database await db.todos.create({ title }); // Return success return { success: true }; } // app/new-todo.js 'use client'; import { createTodo } from './actions'; import { useFormState } from 'react-dom'; export default function NewTodo() { const [state, formAction] = useFormState(createTodo, {}); return ( <form action={formAction}> <input name="title" placeholder="New todo" /> <button type="submit">Create</button> {state.error && <p className="error">{state.error}</p>} </form> ); }
The App Router introduces advanced routing patterns:
// app/@dashboard/page.js export default function Dashboard() { return <div>Dashboard Content</div>; } // app/@sidebar/page.js export default function Sidebar() { return <div>Sidebar Content</div>; } // app/layout.js export default function Layout({ dashboard, sidebar }) { return ( <div className="grid grid-cols-4"> <div className="col-span-1">{sidebar}</div> <div className="col-span-3">{dashboard}</div> </div> ); }
app/feed/page.js
app/feed/[postId]/page.js
app/feed/@modal/(.)post/[postId]/page.js
The Next.js App Router represents a significant evolution in React application development, enabling more performant, maintainable, and user-friendly web applications. By understanding its core concepts and following best practices, developers can build sophisticated applications with improved performance and developer experience.
Full Stack Developer & Security Enthusiast. Passionate about cybersecurity, web development, and innovative technologies.