Frontend Development·9 min

Understanding React Server Components (RSC) in Next.js 15: Deep Dive with Examples

By Bahaj Abderrazak·Published February 12, 2024·Updated September 24, 2026

React Server Components represent the biggest architectural shift in React's history. Understanding when to use Server Components versus Client Components is the key to building fast, maintainable Next.js 15 applications.

# Understanding React Server Components (RSC) in Next.js 15: Deep Dive with Examples React Server Components (RSC) fundamentally change how we think about building user interfaces. Before Server Components, every React component was sent to the browser as JavaScript, parsed, and executed on the client machine — even components that only read static data or rendered simple HTML. In Next.js 15 App Router, **all components are Server Components by default**. Understanding how Server Components differ from traditional Client Components is the single most important skill for modern full-stack React developers. In this deep dive, I explain the mental model, performance benefits, and practical patterns for working with RSC. ## The Mental Model: Server Components vs. Client Components The most important distinction to internalize: - **Server Components** run **only on the server**. They never download to the browser, have access to server-side resources (databases, file systems, internal microservices), and ship **zero JavaScript** to the client bundle. - **Client Components** (designated with `"use client"` at the top of the file) are hydrated in the browser. They are required whenever you need interactive state (`useState`), side effects (`useEffect`), event listeners (`onClick`, `onChange`), or browser APIs (`localStorage`, `window`). | Capability | Server Component (Default) | Client Component (`"use client"`) | |---|---|---| | Direct database access | ✅ Yes | ❌ No | | Access secret server env vars | ✅ Yes | ❌ No (requires API route) | | Ships JS bundle to client | ❌ Zero KB | ✅ Yes | | React state (`useState`, `useReducer`) | ❌ No | ✅ Yes | | Lifecycle hooks (`useEffect`) | ❌ No | ✅ Yes | | Browser event listeners | ❌ No | ✅ Yes | ## Benefit 1: Zero-Bundle Size Libraries Imagine needing to render complex markdown into HTML. With traditional React, you had to bundle markdown parsing libraries (like `marked` or `remark`) into the client JavaScript bundle, adding 50KB to 100KB of download overhead for mobile users. With Server Components, the markdown library stays entirely on the server: ```jsx // app/blog/[slug]/page.jsx — Runs 100% on the server import { marked } from "marked"; import { getArticleFromDatabase } from "@/lib/db"; export default async function BlogPost({ params }) { const { slug } = await params; const article = await getArticleFromDatabase(slug); const htmlContent = marked.parse(article.content); return (

{article.title}

); } ``` The user receives pure, optimized HTML and CSS. The `marked` package is never transmitted across the network. ## Benefit 2: Direct Database and ORM Queries In traditional Single Page Applications (SPAs), fetching data requires creating an API endpoint, defining an HTTP fetch in a `useEffect`, handling loading spinners, and managing error states. In Next.js 15 Server Components, components can be `async` functions that query PostgreSQL or Supabase directly: ```jsx import { supa } from "@/lib/supabaseClient"; export default async function ProjectsList() { // Direct, secure database query during render const { data: projects } = await supa .from("projects") .select("id, title, slug, thumbnail") .order("created_at", { ascending: false }); return (
{projects?.map((project) => ( ))}
); } ``` No API boilerplate. No extra network round-trip between client and server. ## Pattern: Pushing Client Components to the Leaves A common mistake is placing `"use client"` at the top of a page layout or high-level container. This turns all child components into Client Components, forfeiting the performance benefits of Server Components. Instead, **keep the page as a Server Component and push `"use client"` to the leaf interactive elements**: ```jsx // ✅ Good: Server Component page importing a focused interactive button import { LikeButton } from "@/components/LikeButton"; // "use client" export default async function ArticlePage({ params }) { const article = await fetchArticle(params.slug); return (

{article.title}

{article.body}

{/* Only this interactive button ships JavaScript to the client */}
); } ``` ## Streaming with React `` Server Components allow progressive rendering with Suspense. Slow database queries no longer block the entire page from displaying: ```jsx import { Suspense } from "react"; import FastHeader from "@/components/FastHeader"; import SlowAnalytics from "@/components/SlowAnalytics"; import SkeletonLoader from "@/components/SkeletonLoader"; export default function Dashboard() { return (
{/* FastHeader renders instantly; SlowAnalytics streams in when ready */} }>
); } ``` To learn more about modern stack architecture, read [React + Next.js + TypeScript in 2026](/en/blog/react-nextjs-typescript-full-stack-2026) and [React vs Next.js vs Vue](/en/blog/react-vs-nextjs-vs-vue). Need an expert Next.js developer to modernize your frontend or architect a high-performance web app? Explore my [frontend development services](/en/services/frontend-development) or [reach out to discuss your project](/en/contact).
ReactNext.jsServer ComponentsFrontend DevelopmentPerformance

Related articles

Let's begin

Have an idea worth building?

Tell me what you are creating, what stage the project is at, and where you need technical support — I will respond with practical next steps.