App Router Content Sites Need One Data Source Driving Routes, Metadata, and 404s
Most App Router tutorials teach layout, params, and metadata as separate features. This structure shows they are one pipeline: a single data source that determines whether a page exists, what it contains, and how it's described, with the framework handling the failure branch. A developer who wires these together avoids drift between route configs and content.
A small Next.js 16.3.1 project shows how five App Router APIs — layout, dynamic [slug], generateStaticParams, generateMetadata, and notFound — answer one question together: how content gets discovered, located, described, and handled when missing. The key is a single blogPosts array that feeds the list page, detail lookups, build-time static paths, and dynamic page titles, so adding an article never touches multiple route configs. When a slug returns nothing, the page calls notFound(), which re-enters the routing system and lands on a root-level not-found.tsx with recovery links. The project also uses shadcn/ui Button with Base UI's render prop to keep link semantics intact instead of nesting a button inside a link.
Framing layout, dynamic routes, static params, metadata, and notFound as a single pipeline rather than five separate APIs changes how a developer approaches a content site: the question becomes 'what is the source of truth?' rather than 'which file do I create next?'
The project's getBlogPost function is a deliberate boundary. Swapping the static array for a CMS or database only changes that function's internals; every consumer — list, detail, metadata — stays untouched, which is a practical separation that many real projects miss.
Using notFound() instead of returning null is a semantic choice with framework-level consequences: it triggers the correct HTTP status code and lets the root 404 page provide recovery paths, whereas a null render leaves the user stranded with no explanation.