React Server Components in 2026: The Complete Guide to RSC Architecture
React Server Components in 2026: The Complete Guide to RSC Architecture
// app/dashboard/page.tsx (Server Component - no directive needed)
import { db } from '@/lib/database';
import { DashboardChart } from './DashboardChart'; // Client Component
export default async function DashboardPage() {
const analytics = await db.analytics.getMonthly();
const users = await db.users.getActive();
return (
<div className="grid grid-cols-2 gap-4">
<section>
<h2>Monthly Analytics</h2>
{/* Pass server data to client component */}
<DashboardChart data={analytics} />
</section>
<section>
<h2>Active Users: {users.length}</h2>
<UserList users={users} />
</section>
</div>
);
}// app/dashboard/DashboardChart.tsx
'use client';
import { useState } from 'react';
import { BarChart } from 'recharts';
export function DashboardChart({ data }) {
const [timeRange, setTimeRange] = useState('monthly');
return (
<div>
<select onChange={(e) => setTimeRange(e.target.value)}>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</select>
<BarChart data={data[timeRange]} />
</div>
);
}React Server Components (RSC) have fundamentally changed how we architect React applications. With Next.js App Router making RSC the default, understanding this paradigm is essential for every React developer in 2026.
What Are React Server Components?
Server Components are React components that run exclusively on the server. They never ship JavaScript to the client, can directly access databases and file systems, and automatically reduce your client bundle size.
Server vs Client Components
The key distinction:
- Server Components (default in App Router): Run on server, no interactivity, no hooks like useState/useEffect
- Client Components (marked with 'use client'): Run on both server and client, support interactivity and browser APIs
Architecture Pattern: The Donut Model
Think of your component tree as a donut. Server Components form the outer shell (layouts, data fetching, static content), while Client Components are the filling (interactive widgets, forms, animations).
// app/dashboard/page.tsx (Server Component - no directive needed)
import { db } from '@/lib/database';
import { DashboardChart } from './DashboardChart'; // Client Component
export default async function DashboardPage() {
const analytics = await db.analytics.getMonthly();
const users = await db.users.getActive();
return (
<div className="grid grid-cols-2 gap-4">
<section>
<h2>Monthly Analytics</h2>
{/* Pass server data to client component */}
<DashboardChart data={analytics} />
</section>
<section>
<h2>Active Users: {users.length}</h2>
<UserList users={users} />
</section>
</div>
);
}// app/dashboard/DashboardChart.tsx
'use client';
import { useState } from 'react';
import { BarChart } from 'recharts';
export function DashboardChart({ data }) {
const [timeRange, setTimeRange] = useState('monthly');
return (
<div>
<select onChange={(e) => setTimeRange(e.target.value)}>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</select>
<BarChart data={data[timeRange]} />
</div>
);
}