Why App Router Changes Everything
The Pages Router was simple and predictable. The App Router is powerful and nuanced. After shipping 10+ production apps, here are the patterns that actually matter.
Pattern 1: Server Components by Default
Always start with Server Components. Only add "use client" when you genuinely need interactivity, browser APIs, or React hooks. A good rule: if it doesn't have onClick or useState, it probably doesn't need to be a Client Component.
Pattern 2: Colocate Data Fetching
Fetch data as close to where it's used as possible. Avoid prop-drilling data through multiple layers — let each Server Component fetch what it needs directly. This keeps components self-contained and easy to move.
Pattern 3: Parallel Routes for Modals
Instead of managing modal open/close state on the client, use parallel routes with intercepting routes. This gives you shareable URLs, proper back-button behavior, and zero client-side state for something that used to need a useState.
Pattern 4: Streaming with Suspense
Wrap slow data fetches in Suspense boundaries so fast parts of the page render immediately. Users see content progressively instead of staring at a blank screen waiting for the slowest query.
Common Mistakes We've Made
Putting too much in Client Components, forgetting that context providers need "use client", and over-fetching in layouts when a page-level fetch would do.
Conclusion
The App Router rewards patience. Once the mental model clicks — server first, client only when needed — everything becomes faster to build and faster to ship.