Next.js 16 sharpened a lot of the App Router conventions. Here are the pieces I reach for most often now.
Route params are async
Dynamic route params are a Promise you await inside the component. Once you
internalize it, it reads cleanly:
export default async function Post({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
return <article>Reading: {slug}</article>;
}
Static params for pre-rendering
For a static blog, every post should be generated at build time. generateStaticParams
enumerates the slugs, and the pages fall out as static HTML:
export function generateStaticParams() {
return getAllPosts().map((post) => ({ slug: post.slug }));
}
Metadata is data, not markup
Per-page <title>/description come from an exported metadata object (or an
async generateMetadata) rather than JSX in the head — which keeps the render
path focused on content.
None of this is dramatic on its own, but together it makes a content site pleasant to build: the framework does the static generation, and I just describe the data.