Next.js & Web
Structure App Router routes, server and client components, metadata, and data fetching the way Next.js 15+ actually wants.
1 file
Description
Structure App Router routes, server and client components, metadata, and data fetching the way Next.js 15+ actually wants.
Any work under an app/ directory: adding a route, splitting a component into client and server halves, wiring metadata, or debugging why a page is a client bundle when it should be static.
app/ is a Server Component by default. Add "use client" only on the leaf that needs state, effects, or browser APIs. Pushing "use client" up to a page turns the whole subtree into a client bundle.page.tsx. Shared shell is layout.tsx. Loading UI is loading.tsx. Error UI is error.tsx and must be a client component.Create app/thing/[slug]/page.tsx as a server component.
Export generateStaticParams returning every slug so the route is statically generated:
export async function generateStaticParams() {
const items = await getAllItems();
return items.map((i) => ({ slug: i.slug }));
}
Export generateMetadata for a per-page title, description, and canonical:
export async function generateMetadata({ params }): Promise<Metadata> {
const { slug } = await params;
const item = await getItem(slug);
return {
title: item.title,
description: item.excerpt,
alternates: { canonical: \`/thing/\${slug}\` },
};
}
Return notFound() from next/navigation for unknown slugs so you get a real 404, not a soft empty page.
params and searchParams are Promises. Await them. A synchronous params.slug read compiles but is undefined at runtime.export const metadata and generateMetadata cannot both live in the same file. Pick one."use client" file leaks it into the browser bundle. Guard server modules with import "server-only".Added 2026-07-01. Back to the Skill Library.

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.