Server Components are Component that renders ahead of time, before bundling, in an environment separate from your client app or SSR server. This separate environment is the “server” in React Server Components. Server Components can run once at build time on your CI server, or they can be run for each request using a web server.
React Server Components (RSC) fundamentally change the execution model of React applications [citation:7]. Unlike traditional components that run in the browser (Client Components), Server Components execute and render in a separate environment before the bundling process, either at build time or for each request on a web server [citation:4].
The key innovation is that these components are not sent to the client at all [citation:7]. Instead, React serializes their output into a format (the RSC Payload) that is streamed to the client and seamlessly integrated with Client Components [citation:1][citation:3]. This architecture directly addresses the longstanding tension between performance and interactivity: you can keep heavy data-fetching logic and large libraries on the server, eliminating them from the client bundle, while still preserving rich interactivity where you need it [citation:9].
RSCs are not a replacement for traditional SSR but a complementary layer [citation:3][citation:7]. You can think of the architecture as having two distinct component categories with a clear boundary defined by modules, not the render tree [citation:3][citation:10]:
Server Components: Run exclusively on the server. They have direct access to backend resources (databases, file systems) and cannot use interactive APIs like useState, useEffect, or browser events [citation:1][citation:5]. Their heavy dependencies don't impact the client bundle.
Client Components: Marked with the 'use client' directive. They run on the server once to generate initial HTML and then hydrate on the client to become interactive, using standard React hooks and browser events [citation:3][citation:5].
Seamless Composition: The model's power lies in how these components compose. A Server Component can import a Client Component to add interactivity, while a Client Component can accept Server Components as children or props, preserving their server-rendered output [citation:3][citation:8].
Zero Bundle Size for Server Code: The most dramatic benefit is that the code for Server Components and any server-only dependencies (like heavy libraries or database ORMs) is never sent to the client [citation:1][citation:9]. This drastically reduces client-side JavaScript, improving initial load times.
Simplified Data Fetching: RSCs eliminate the need for separate API endpoints or useEffect hooks to fetch data [citation:1][citation:5]. An async Server Component can directly await data from your database, streamlining your code and eliminating client-server waterfalls [citation:9].
Improved Performance Metrics: By moving work to the server and reducing client-side JavaScript, RSC leads to faster Time to Interactive (TTI) and smaller client bundles. A study by Aha! engineering reported a 90% reduction in JavaScript and an 80% drop in time-to-interactive after migrating to an RSC architecture [citation:6].
It is crucial to distinguish React Server Components from Server-Side Rendering (SSR). SSR runs your entire React app on the server for every request to generate HTML, but it still sends the component code to the client for hydration [citation:1][citation:7].
RSC takes this a step further by keeping the component code on the server permanently. The component's output is rendered, but its logic and dependencies never leave the server, leading to the dramatic bundle size reductions mentioned above. In a typical framework implementation (like Next.js App Router), RSC and SSR are used together: RSC handles the data fetching and static composition, while SSR generates the initial HTML payload for the fastest possible first paint [citation:3][citation:7].
Requires a Framework: You cannot use RSC in a plain React project. You need a framework that supports them, such as the Next.js App Router, Remix, or TanStack Start [citation:1][citation:4][citation:10].
No Client-Side Interactivity: By definition, Server Components cannot use state, effects, or event handlers. All interactivity must be delegated to Client Components composed within them [citation:3][citation:5].
Serialization Constraint: Props passed from a Server Component to a Client Component must be serializable, as they are sent over the network in the RSC payload [citation:3].
In summary, React Server Components represent a paradigm shift, not just another rendering method [citation:9]. They allow developers to build full-stack components that render on the server without impacting client bundle size, effectively giving us the performance of a static site with the dynamic capabilities of a server-rendered application [citation:8].
With Server Components, you can render components once at build time.
The rendered output can then be server-side rendered (SSR) to HTML and uploaded to a CDN. When the app loads, the client will not see the original Page component, or the expensive libraries for rendering the markdown. The client will only see the rendered output
This means the content is visible during first page load, and the bundle does not include the expensive libraries needed to render the static content.
Server Components can also run on a web server during a request for a page, letting you access your data layer without having to build an API.
Without Server Components, it’s common to fetch dynamic data on the client in an Effect via an api, but using server components we can directly read the data from db.
The bundler then combines the data, rendered Server Components and dynamic Client Components into a bundle. Optionally, that bundle can then be server-side rendered (SSR) to create the initial HTML for the page. When the page loads, the browser does not see the original Note and Author components; only the rendered output is sent to the client
Server Components are not sent to the browser, so they cannot use interactive APIs like useState. To add interactivity to Server Components, you can compose them with Client Component using the 'use client' directive.
A common misunderstanding is that Server Components are denoted by 'use server', but there is no directive for Server Components. The 'use server' directive is used for Server Functions.