React Server Components Change Everything
The Next.js App Router is not just a routing upgrade — it is a fundamental shift in how you think about data fetching and rendering. After rebuilding five production applications on App Router in 2024, here is our opinionated take on what the performance patterns are.
Pattern 1: Fetch as Close to the Data as Possible
With RSC you can fetch data directly inside a Server Component without an API round-trip. Fetch at the leaf level, not the root. This enables component-level caching and means a cache miss for one component does not invalidate the entire page.
// ✅ Good — leaf-level fetch with component-scoped cache
async function UserCard({ userId }: { userId: string }) {
const user = await fetch(`/api/users/${userId}`, {
next: { revalidate: 60 }
}).then(r => r.json());
return <div>{user.name}</div>;
}
Pattern 2: Parallel Data Fetching with Promise.all
Sequential awaits in a Server Component create a waterfall. Use Promise.all to fetch independent data sources in parallel.
Pattern 3: Streaming with Suspense for Perceived Performance
Wrap slow data-dependent components in <Suspense> with a skeleton fallback. The page shell renders instantly (great for LCP) and the slow sections stream in progressively. This is the single highest-impact change we make when migrating apps to App Router.
Pattern 4: Partial Prerendering (PPR) for Mixed Pages
PPR (experimental in Next.js 14, stable in 15) lets you statically prerender the page shell at build time while streaming dynamic holes at request time — combining the best of SSG and SSR. Enable it per-route with export const experimental_ppr = true.
Pattern 5: Avoid "use client" at the Top of Trees
The most common App Router performance anti-pattern: marking a parent layout as a Client Component because one child needs interactivity. Instead, push the "use client" boundary down to only the interactive component. Keep the surrounding tree as Server Components.
Results
Applying these patterns when migrating a SaaS dashboard (previously Pages Router) to App Router: LCP improved from 3.2s to 0.8s, TBT from 420ms to 60ms, Lighthouse performance score from 72 to 97.

