Next.js App Router: A Practical Guide for 2025
The App Router replaced the old Pages Router as the default in Next.js, and it changes more than just the folder structure — it changes how you think about rendering. Here's the mental model that finally made it click for me.
Everything Is a Server Component by Default
Every component inside app/ renders on the server unless you explicitly opt out with 'use client' at the top of the file. That single line is the boundary between server and client — everything below it, and everything it imports, ships to the browser.
File-Based Layouts
app/
layout.tsx // shared shell
page.tsx // route: /
blog/
layout.tsx // nested shell for /blog/*
page.tsx // route: /blog
[slug]/
page.tsx // route: /blog/my-post
Layouts persist across navigations within their segment — they don't re-render when you move between child pages, which is why they're the right place for things like a sidebar or nav bar.
Data Fetching Without useEffect
export default async function Page() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return <PostList posts={posts} />;
}
Server components can be async directly. No loading state, no useEffect, no client-side waterfall — the HTML arrives already populated.
When You Actually Need 'use client'
- Anything using
useState,useEffect, or other hooks - Event handlers like
onClick - Browser-only APIs (
window,localStorage)
The best pattern is pushing client components as far down the tree as possible — keep the shell and data-fetching on the server, and isolate interactivity into small leaf components.