Back to Blog

5 Critical Performance Optimizations for React Server Components

OptimizationNext.jsReactPerformance

React Server Components (RSC) fundamentally changed how we build React applications. By moving the rendering to the server, we ship zero JavaScript to the client for static UI. However, if implemented poorly, RSCs can actually hurt your performance by introducing severe server-side latency.

Here are 5 critical optimizations for your Next.js applications.

1. Eliminate Data Waterfalls with Promise.all

The most common mistake in Next.js App Router is sequential data fetching. If you await a user profile, and then await their posts, you've created a waterfall.

Bad:

const user = await getUser(id);
const posts = await getPosts(id); // Waits for user to finish!

Good:

const userPromise = getUser(id);
const postsPromise = getPosts(id);

// Fetches both in parallel
const [user, posts] = await Promise.all([userPromise, postsPromise]);

2. Granular Suspense Boundaries

You don't want your entire page to block rendering just because a slow API request is taking 3 seconds. Wrap slow components in <Suspense> boundaries. Next.js will stream the fast parts of the UI (like the navbar and sidebar) immediately, and then stream the slow component when it's ready.

import { Suspense } from 'react';
import { SkeletonCard } from '@/components/skeletons';

export default function Dashboard() {
  return (
    <div>
      <Sidebar />
      <Suspense fallback={<SkeletonCard />}>
        <HeavyDataGrid />
      </Suspense>
    </div>
  );
}

3. Optimizing Images with Next-Gen Formats

Never serve raw PNGs or JPEGs. Ensure your next.config.ts is configured to output AVIF and WebP formats. AVIF is 20% smaller than WebP and 50% smaller than JPEG.

// next.config.ts
const nextConfig = {
  images: {
    formats: ['image/avif', 'image/webp'],
  },
};

4. Push Client Component Leaves Down

Only use 'use client' at the absolute lowest leaf of your component tree. If you make a layout or a parent wrapper a Client Component, every child inside it becomes a Client Component, bloating your JavaScript bundle.

Pass Server Components as children props to Client Components to preserve their server-rendered nature.

5. Aggressive Route Segment Caching

Use export const revalidate = 3600; on static pages (like blogs or marketing sites) to instruct Next.js to cache the rendered HTML at the CDN level. This means subsequent visitors hit a cached HTML file globally distributed, resulting in sub-50ms response times.