Cansu Arı Logo
Blog
What is it?

React 19 & Server Components: Is the Browser or the Server Rendering?

With React 19, Server Components reshape UI architecture. Some components never reach the browser—less JS, more performance!

  • #React
  • #React 19
  • #Performance

Skip to content

Browser or server—who renders now?

React 19 marks one of the framework’s biggest architectural shifts.
Server Components (RSC) are officially stable. Some components render entirely on the server and never ship client-side JavaScript.

Sounds like magic, right? ✨
It’s actually the web’s natural evolution. Let’s unpack it.


Classic model (Client Components)

Historically, React was browser-first. Every component shipped in the JS bundle and became interactive after hydration.
function Hello() {
return <h1>Hello Client!</h1>
}
Even if HTML was server-rendered, the component still needed to load JS in the browser. HTML + JS = a React page.

⚠️ Problem: bundles grow huge on large apps; startup slows.


New model: Server Components (RSC)

With React 19, some components render only on the server and send HTML output to the client. They don’t add to the browser bundle.
// Server Component
export default async function Posts() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return (
<ul>
{posts.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
);
}
This ships as HTML—no client JS to hydrate.

Traits of a Server Component

PropertyMeaning
ExecutionServer
Ships JS to client?No
Can fetch data?Yes (fetch/DB/API)
Hooks allowedOnly non-interactive ones (no useEffect/useState)
Re-renderTriggered server-side as needed
In short: Server Components process data on the server and stream HTML.

Mixing Client & Server Components

React 19 lets you combine both.
// 📁 app/page.jsx
import Posts from './Posts.server';
import LikeButton from './LikeButton.client';

export default function Page() {
return (
<main>
<Posts />
<LikeButton />
</main>
);
}
  • Posts.server → Server Component (fetches, returns HTML).
  • LikeButton.client → Client Component (interactivity).
React splits and handles them automatically: server renders, client hydrates.

How RSC works

Server Components use React’s Flight protocol. The server sends a special JSON-like stream describing the render. The client resolves it into HTML and stitches it into the tree.

Benefits:

  • Smaller JS bundles
  • Less client rendering
  • A better SSR–SPA balance



Real-world example (Next.js 15)


In Next.js 15, Server Components are the default in app/.

// app/posts/page.jsx
export default async function Page() {
const posts = await getPosts();
return (
<>
<h1>Latest Posts</h1>
<ul>
{posts.map(p => <li key={p.id}>{p.title}</li>)}
</ul>
</>
);
}
These render server-side without sending JS. Interactive parts are marked with use client:
'use client'
export function LikeButton() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>❤️ {count}</button>;
}

Result: the page may ship ~3 KB of JS—only for the button.


Pros & watch-outs

✅ Advantages

  • Dramatically smaller JS bundles
  • Faster data access on the server
  • Better security (keys stay server-side)
  • Excellent SEO (HTML is complete)

Considerations

  • useEffect/useState aren’t available in server components.
  • Share data with client components via props.
  • Pay attention to cache strategy.
Best practice: render static/readonly UI on the server; keep interactions on the client.

Data flow with RSC

Server components are async; fetch inside the component—no useEffect needed.
export default async function ProductList() {
const products = await fetch('/api/products').then(r => r.json());
return <div>{products.map(p => <Product key={p.id} {...p} />)}</div>;
}
Fetching and rendering become one step, reducing the need for client-side data libs.

Performance impact

  • ~30% faster TTFB on average
  • Up to 40% smaller bundles
  • Shorter hydration = lower CPU
Benchmarks also show ~25% less battery drain on mobile. ⚡

More in React 19

  • use() hook → await async data directly in components
  • Actions API → handle form submits on the server
  • Suspense integrates tightly with data fetching
export default function Page() {
const data = use(fetchData());
return <div>{data.title}</div>;
}

Conclusion

React 19’s Server Components blur the line between front end and back end. Less JavaScript reaches the browser; pages get faster; the developer workflow simplifies.

In short:

  • Server Components = less JS, more speed
  • Client Components = interactivity and animation
  • Using both together = the future of the web

All tags
  • React
  • React 19
  • Performance