Next.js
A concept-first tour of Next.js — routing, Server vs Client Components, data fetching, and mutations — building on React.
Next.js is the most widely used React framework: it takes React's component model and adds the pieces a real app needs — file-based routing, server rendering, data fetching, and a production build — with sensible defaults. This guide assumes you know the React basics; if not, start with the React guide. Examples target Next.js 16 with the App Router.
Next.js 16 defaults: the App Router (the app/ directory), Turbopack as the bundler, and
React 19. The older pages/ router still works but new projects should use app/.
Creating a project
create-next-app scaffolds a project with everything wired up — TypeScript, the App Router, and a
dev server.
npx create-next-app@latest my-app
cd my-app
npm run dev # Turbopack dev server on http://localhost:3000File-based routing
Routes are folders, not configuration. A folder under app/ becomes a URL segment, and a
page.tsx inside it makes that segment publicly routable. A layout.tsx wraps every page beneath
it with shared UI (nav, footer) that persists across navigation.
// Wraps all routes; rendered once and kept across navigations
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}// Becomes the /about route
export default function About() {
return <h1>About us</h1>;
}Server vs Client Components
This is the core mental shift from plain React. In the App Router, components are Server
Components by default: they render on the server, can talk to your database or filesystem
directly, and ship zero JavaScript to the browser. Add the "use client" directive at the top
of a file only when a component needs interactivity — state, effects, or event handlers.
// Server Component (default): no "use client", runs on the server
export default function Page() {
return <p>Rendered on the server.</p>;
}"use client"; // opt in to the browser: needed for useState, onClick, etc.
import { useState } from "react";
export default function Counter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>{n}</button>;
}Dynamic routes
A folder named in square brackets captures part of the URL as a parameter. The page receives it
via params — which in Next.js 16 is a Promise you must await (a change from older
versions).
export default async function Post({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params; // params is async in Next.js 16
return <h1>Post: {slug}</h1>;
}Fetching data
Because Server Components run on the server, data fetching is just async/await inside the
component — no useEffect, no loading-state plumbing, no client round-trip. The component renders
once the data resolves.
export default async function Penguins() {
const res = await fetch("https://example.com/penguins.json");
const penguins: { id: number; species: string }[] = await res.json();
return (
<ul>
{penguins.map((p) => (
<li key={p.id}>{p.species}</li>
))}
</ul>
);
}Mutating data with Server Actions
A Server Action is an async function marked "use server" that runs on the server but can be
called from the client — including straight from a form's action. It's the modern way to handle
mutations without hand-writing an API route.
export default function NewPost() {
async function create(formData: FormData) {
"use server";
const title = formData.get("title");
// ...write to your database here
}
return (
<form action={create}>
<input name="title" />
<button type="submit">Create</button>
</form>
);
}Linking and navigation
Use next/link for navigation between routes. It renders an <a> but does client-side
transitions and prefetches linked pages in the background, so navigation feels instant.
import Link from "next/link";
export default function Nav() {
return <Link href="/about">About</Link>;
}Metadata
Export a metadata object (or an async generateMetadata function) from a page or layout, and
Next.js renders the right <head> tags — titles, descriptions, Open Graph — for SEO and sharing.
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "About us",
description: "Who we are.",
};
export default function About() {
return <h1>About us</h1>;
}Next.js 16 changes worth knowing
A few defaults changed recently: params, searchParams, cookies(), and headers() are now
async (always await them); the middleware file was renamed from middleware.ts to
proxy.ts; Turbopack is the default bundler; and next lint was removed in favor of
running ESLint or Biome directly. The npx @next/codemod@canary upgrade latest codemod automates
most of these migrations.