Next.js 15 App Router: The Notes I Wish I Had on Day One
A practical, opinionated tour of Server Components, data fetching and rendering modes in the App Router.
Kamal Benaouija
June 10, 2026
I rebuilt my own site on Next.js 15's App Router while writing this, so these notes are fresh — not theoretical.
Server Components Are the Default, and That's the Point
Every component in app/ is a Server Component unless you opt into "use client". That single default changes how you should think about data fetching entirely.
// app/projects/page.tsx — this runs on the server, no client JS shipped for this logic
import { getAllProjects } from "@/lib/projects";
export default function ProjectsPage() {
const projects = getAllProjects();
return <ProjectGrid projects={projects} />;
}No useEffect, no loading spinner, no client-side waterfall. The data is just... there, before the HTML ever reaches the browser.
When You Actually Need "use client"
Reach for a Client Component only when you need:
- Interactivity (
onClick,onChange, state) - Browser-only APIs (
window,localStorage) - React hooks like
useStateoruseEffect
Everything else — layout, data fetching, static content — should stay a Server Component. Push "use client" as far down the tree as possible.
Rendering Modes, Simplified
| Mode | When it runs | Use for |
|---|---|---|
| Static (default) | Build time | Pages with no per-request data |
| Dynamic | Per request | Pages using cookies, headers, or no-store fetches |
| Streaming | Per request, incrementally | Pages with slow, non-critical data |
Next.js infers the mode automatically based on what your code does — no explicit config needed for most cases.
Metadata Without the Boilerplate
The built-in Metadata API replaces manual <head> management entirely:
export async function generateMetadata({ params }) {
const post = await getPostBySlug(params.slug);
return {
title: post.title,
description: post.description,
};
}Combined with app/sitemap.ts-style generation and JSON-LD, this alone removes the need for most third-party SEO libraries in the App Router.
My One Piece of Advice
Resist the urge to make everything a Client Component "just in case." Every unnecessary "use client" boundary is JavaScript your visitors have to download and execute for no reason. Default to the server; earn your way to the client.
