React Server Components (RSC) represent the biggest architectural shift in React since hooks. With Next.js 15 stabilizing the App Router and Server Components, it’s time to understand what changes and how to use them effectively.
What Are Server Components?
Server Components run on the server and never ship JavaScript to the client. They can directly access databases, read files, and use server-only APIs. The result is HTML sent to the browser with zero client-side JavaScript overhead.
The key insight: not every component needs to be interactive. Navigation links, static content, data displays, and layout structures are perfect candidates for Server Components. Only the pieces that need interactivity — buttons, forms, modals — become Client Components.
Server vs Client Components: When to Use Each
Use Server Components when:
- Fetching data from databases or APIs
- Accessing backend resources directly
- Rendering static or semi-static content
- Keeping sensitive logic on the server
- Reducing client-side JavaScript bundle size
Use Client Components when:
- Adding interactivity (onClick, onChange, etc.)
- Using state (useState, useReducer)
- Using effects (useEffect)
- Using browser-only APIs (localStorage, geolocation)
- Custom hooks that depend on state or effects
Streaming SSR and Suspense
Next.js 15 leverages streaming SSR to progressively send HTML to the browser. Combined with React Suspense, you can show fallback UI while data is loading, then stream in the actual content when ready. This eliminates the “loading spinner” problem of traditional SSR.
Wrap your data-fetching Server Components in Suspense boundaries and React will progressively render each section as its data becomes available. The browser paints content immediately rather than waiting for the entire page.
Performance Impact
In our projects, migrating from Pages Router to App Router with Server Components has consistently reduced JavaScript bundle sizes by 40-60%. Pages that previously shipped 200KB of JavaScript now ship 50KB or less. First Contentful Paint improves by 30-50% because the browser receives meaningful HTML immediately.
Common Patterns We Use
Data fetching: Server Components fetch data directly with async/await. No useEffect, no loading states in components, no client-side fetching libraries needed for initial data.
Composition: Server Components can render Client Components as children. Use this to create a “shell” that fetches data on the server, then passes it to interactive client components.
Server Actions: Form submissions and mutations handled entirely on the server with progressive enhancement. Works even without JavaScript enabled.
Migration Strategy
Don’t rewrite everything at once. Start by migrating layout components to Server Components. Then gradually move data-fetching logic out of useEffect and into Server Components. Leave interactive pieces as Client Components. The incremental approach lets you measure performance improvements at each step.
Need help with your project?
Our team specializes in building production-grade software. Explore our services:
Get engineering insights in your inbox
Production-tested approaches to AI, Laravel, React and more. No spam, unsubscribe anytime.


