← Blog

Notes on building with Next.js 16

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.