The Power of Server Components in Next.js 13
React Server Components flip the default: components render on the server unless you opt into the client. Less JavaScript ships to the browser, data fetching happens next to the data, and secrets never leave the server.
Server by Default
In the App Router, every component is a Server Component unless the file starts with the "use client" directive. A server component can be async and await data directly — no useEffect, no loading state juggling:
// app/posts/page.tsx — a Server Componentexport default async function PostsPage() { const posts = await db.post.findMany({ orderBy: { date: 'desc' } }); return ( <ul> {posts.map((p) => <PostCard key={p.id} post={p} />)} </ul> );}When You Need the Client
Interactivity — state, effects, event handlers — still lives in Client Components. The trick is to push them to the leaves of the tree so the interactive islands stay small:
'use client'; export function LikeButton({ postId }: { postId: string }) { const [liked, setLiked] = useState(false); return <button onClick={() => setLiked(!liked)}>{liked ? "♥" : "♡"}</button>;}The result: a page that is mostly static HTML streamed from the server, with small hydrated islands where the user actually interacts. Bundle sizes drop, Time to Interactive improves, and the data layer stays simple.
Streaming and Suspense
Server Components pair naturally with Suspense. Wrap slow sections in a Suspense boundary and Next.js streams the shell immediately, filling in each section as its data resolves. The user sees meaningful content in milliseconds instead of staring at a spinner while the slowest query finishes:
<Suspense fallback={<PostsSkeleton />}> <Posts /> {/* awaits its own data */}</Suspense><Suspense fallback={<SidebarSkeleton />}> <TrendingSidebar /> {/* streams independently */}</Suspense>Think of it as parallelism for free: each boundary is its own loading unit, and the framework coordinates the streaming. Combined with fetch-level caching and revalidation, you get pages that are fast on first visit and nearly instant after — without writing a single client-side data hook.