Next.js App Router rewrote the rules for caching, state, and rendering, and plenty of teams shipped stale-data bugs before they understood the new model. The pitfalls below cost days of debugging in real projects. Every one passed code review before the incident.
Why does my data look stale?
Caching is aggressive by default: fetch requests enter the Data Cache and route segments stay cached until you say otherwise. Stale data bugs trace back to defaults nobody chose. force-dynamic, revalidatePath, and revalidateTag become daily vocabulary; learn each one before your first deploy, not after your first ticket.
What can cross the Server-to-Client Component boundary?
The boundary serializes props: functions, class instances, and complex objects throw serialization errors at runtime. Composition with children solves most cases; the Server Component builds the tree and passes finished JSX down. For executable logic on the client, inject custom hooks instead of pushing functions across the line.
Why is my page so slow to load?
Nested await calls inside Server Components turn parallel work into a waterfall: the product fetch waits on the user fetch, which waits on the session. Promise.all parallelizes what has no dependency between calls, and Suspense boundaries restore streaming for whatever can arrive later. A three-level waterfall multiplies network latency by three.
How do you fix hydration errors?
Date objects and random values diverge between the server render and the client render, producing mismatch warnings. Use deterministic serialization: ISO string timestamps, IDs generated outside render, values formatted with a fixed locale. The warning disappears, and so does the production mystery.
Do Route Handlers replace API routes?
App Router handlers stream out of the box, but cookie and header access changes shape compared with the Pages Router. Middleware runs before everything, static assets included, unless the matcher config excludes those paths. Without exclusion, every image request walks through your auth middleware.
Are Server Actions fit for mutations?
Server Actions simplify forms yet still expose POST endpoints; check authentication and authorization inside every action. Redirect after the mutation to prevent double submits on refresh. Validate input with zod the way you would on a public API.
Why did my bundle explode?
Importing a server-side library into a Client Component bloats bundles until builds fail or pages crawl. The server-only package enforces the boundary at import time and turns forgetfulness into a build error. Run the webpack analyzer once in a while; bundle drift arrives without notice.
What changes at deployment time?
- Self-hosting needs the Node runtime for ISR and image optimization
- The edge runtime restricts libraries: no fs, no native database drivers
- Platform-specific features require adapters outside Vercel
Enjoyed this content?
I build web products and AI solutions the right way — solid architecture, maintainable code, and real delivery.
Let's talk