Using React Server Components to Trim Your Bundle Size
Learn how React Server Components let you render UI on the server, stream HTML, and cut client‑side JavaScript without rewriting your app.
20 Jul 2026, 05:16 UTC

Problem: Too Much JavaScript for Mostly Static UI
Many React applications ship a large client‑side bundle because components that never need interactivity—like a profile card, a marketing banner, or a footer—are still sent to the browser as JavaScript. Even though these pieces render the same HTML on every request, the browser must download, parse, and execute their code, which adds to load time and hurts performance on slower connections.
Thesis: Move Static Parts to the Server with React Server Components
React Server Components (RSC) let you render a component on the server, stream its HTML to the client, and keep the component’s code out of the client bundle. The server‑rendered HTML can be hydrated later only if the component needs interactivity; otherwise the client receives pure HTML with zero JavaScript cost. This approach reduces bundle size while preserving the familiar React programming model.
How React Server Components Work
When a component is marked as a server component (by convention, using a .server.js or .server.jsx extension or via your bundler’s plugin), React renders it on the server. The result is a stream of HTML fragments that the client can display as they arrive. Suspense boundaries are used to show placeholders while data is being fetched. Because the server component’s code never travels to the client, the client‑side bundle excludes it, shrinking the download size.
Setting Up a Minimal Vite Project with RSC
To experiment with RSC you need a bundler that understands the React Server Compiler. The Vite plugin vite-plugin-react-swc (or the Next.js integration) can compile server components. Below is a basic setup:
- Initialize a Vite + React project:
npm create vite@latest my-rsc-app -- --template react - Install the compiler plugin:
npm i -D vite-plugin-react-swc - Add the plugin to
vite.config.js:
import { defineConfig } from 'vite';
import reactSwc from 'vite-plugin-react-swc';
export default defineConfig({
plugins: [reactSwc()],
});
Now you can create a server component by naming the file ProfileCard.server.jsx. The plugin treats any file ending in .server.jsx as a server component.
Worked Example: Moving a Profile Card to the Server
Suppose you have a simple profile card that only displays static data fetched from an API:
// ProfileCard.server.jsx
export default async function ProfileCard() {
const res = await fetch('https://api.example.com/user/123');
const user = await res.json();
return (
{user.name}
{user.bio}
);
}
In a regular client component you would import and use it like any other React component:
// App.jsx
import ProfileCard from './ProfileCard.server.jsx';
export default function App() {
return (
Loading profile…}>
);
}
When the dev server runs, the server component executes on the Node process, fetches the user data, and streams the resulting HTML to the browser. The client receives the HTML inside the Suspense
ProfileCard function’s code.
Checking the Bundle Size Impact
To verify that the server component’s code is omitted from the client bundle, run a production build and inspect the output:
- Run
npm run build(Vite will produce adistfolder). - Open the generated JavaScript file (usually
dist/assets/index.-.js) in a text editor. - Search for the string
ProfileCard. You should not find the component’s function definition; only the HTML markup that was streamed appears in the response. - Optionally, use a bundle‑visualizer plugin like
rollup-plugin-visualizerto see the reduced size of the client chunk.
Comparing the build size before and after moving the component to the server typically shows a reduction equal to the size of the component’s code plus any dependencies it imported (e.g., the fetch polyfill or UI library).
Trade‑offs and Limitations
- Server components cannot use client‑only hooks such as
useState,useEffect, oruseReducer. If you need interactivity, you must split the UI into a server component for the static part and a client component for the interactive part. - Debugging requires awareness of the server/client boundary; console logs in a server component appear in the server terminal, not the browser devtools.
- Not all npm packages are compatible with the server environment; packages that rely on
windowordocumentwill throw errors when imported in a server component. - You need a bundler and server runtime that support the React Server Compiler (Vite with the SWC plugin, Next.js, or a custom Node server). Setting this up adds build‑step complexity.
Actionable Closing
If your application contains large chunks of UI that never change after the initial render—such as static marketing sections, documentation pages, or data‑display widgets—consider moving them to React Server Components. Start by identifying a component that only reads props or fetches data, rename it with the .server.jsx suffix, and ensure your bundler is configured with the React Server Compiler. Verify the change by checking that the component’s code disappears from the client bundle and that the page still renders correctly. Over time, you can migrate more components, trimming JavaScript sent to the browser and improving load performance without rewriting your app’s core logic.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.