Notes on the Next.js App Router after shipping it to production
Things I wish I'd known before migrating a real app from Pages Router to the App Router.
Table of contents
I finished a migration from the Pages Router to the App Router last month. Here are the notes I'd give my past self.
Server components are the point
If you treat the App Router as "Pages Router with new file names," you'll have
a bad time. The whole model only pays off once you lean into server
components by default and push "use client" as far down the tree as you
can. Data fetching moves to the component that needs it. Props stop being a
waterfall.
generateStaticParams is your friend
For content-heavy sites, generateStaticParams gives you the same SSG
guarantees as the old getStaticPaths, with less ceremony:
export function generateStaticParams() {
return getAllPostSlugs().map((slug) => ({ slug }));
}Combine it with generateMetadata and you get fully static, SEO-friendly pages
without any of the old getStaticProps plumbing.
Metadata API: use it
Don't hand-roll <head> tags. The metadata API handles titles, descriptions,
Open Graph, Twitter cards, canonicals, and the rest with full type safety.
Template titles
Setting a template in the root layout means every page gets a branded title for free:
title: {
default: siteConfig.title,
template: `%s — ${siteConfig.name}`,
}Things that bit me
searchParamsandparamsare now promises in newer versions —awaitthem in server components.- Client components can't import server-only modules. If you accidentally pull
in
fsthrough a shared util, the error message is unhelpful. next/imagein MDX needs you to map theimgcomponent explicitly.
Would I do it again
Yes. The mental model is cleaner once it clicks, and the defaults push you toward better performance.