Back to Blog
Next.jsReactServer ComponentsApp RouterPerformance

Next.js App Router & Server Components: A Practical Guide for Frontend Developers

M
Meysam Kiani
··7 min read

What Are React Server Components?

React Server Components (RSC) are components that render exclusively on the server. Unlike traditional React components, they never ship JavaScript to the client — which means your bundle stays small and your page loads fast.

Next.js was one of the first frameworks to bring RSC into production through the App Router, introduced in Next.js 13 and stabilized in version 14+.

Why This Matters for Frontend Developers

Before RSC, fetching data on the server required either getServerSideProps (Pages Router) or client-side hooks like SWR or React Query. Both approaches have trade-offs: either you're blocking the whole page, or you're shipping extra JavaScript to handle loading states.

Server Components solve this cleanly:

  • Zero bundle cost — server-only code never reaches the browser
  • Direct data access — query your database or API directly inside the component
  • Streaming — Next.js can send HTML to the browser progressively using React's Suspense

Server vs Client Components

The key mental model is simple: by default, everything in the app/ directory is a Server Component. To opt into client-side interactivity, you add the "use client" directive at the top of a file.

// Server Component — no directive needed
async function UserProfile({ id }: { id: string }) {
  const user = await db.users.findById(id); // direct DB call, no API needed
  return <h1>Hello, {user.name}</h1>;
}
"use client"; // Client Component

import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

When to Use Each

Use Server Components when:

  • Fetching data (from a database, API, CMS)
  • Rendering static or mostly-static content
  • Working with secrets (API keys, tokens) that shouldn't reach the client
  • Improving Core Web Vitals — especially LCP

Use Client Components when:

  • Using React hooks (useState, useEffect, useContext)
  • Handling browser events and interactivity
  • Using browser-only APIs (localStorage, window, etc.)
  • Working with third-party libraries that require DOM access

A Real-World Pattern: The Data Fetching Tree

One pattern I've found powerful in production is composing Server and Client components together:

// Server Component — fetches data
async function ProjectsPage() {
  const projects = await fetchProjects();
  return <ProjectList projects={projects} />;  // Client Component for interactivity
}

The server renders the data, the client handles the UX. Clean separation.

Performance Impact

In my work on projects like SliceGames.io, switching to RSC-first architecture reduced Time to First Byte (TTFB) significantly and improved Core Web Vitals scores — which directly translates to better SEO rankings.

The takeaway: if you're building a Next.js app in 2025 and not leveraging Server Components, you're leaving significant performance on the table.

Getting Started

1. Use the App Router (app/ directory) — it's stable and the future of Next.js

2. Default to Server Components; add "use client" only when you need it

3. Use Suspense boundaries to stream non-critical UI

4. Pair with the cache() function or unstable_cache for intelligent data memoization

Server Components aren't just a new API — they're a new mental model for splitting your application. Once it clicks, you'll wonder how you shipped without them.

Enjoyed this article?

Check out my work

Let's build something great together

Get in Touch

Whether it's a full-time role, a freelance project, or just a great idea — I'm always happy to chat.