DEV

Client vs Server Components in Next.js 13 Explained

Jul 29, 2025

client vs server JS
client vs server JS

Next.js 13 introduced a powerful shift in how React components are rendered — with Server Components as the default and Client Components only when needed.

This new model helps developers create faster, more efficient applications by reducing the amount of JavaScript sent to the browser. But it also introduces some new patterns and rules that can feel confusing at first.

In this post, you’ll learn:

  • What Server and Client Components are

  • How they work in the App Router

  • When to use each type

  • Common pitfalls and best practices

🧠 What Are Server and Client Components?

Let’s break it down:

🖥️ Server Components

  • Render on the server — no JavaScript sent to the browser

  • Have access to server-only data (e.g., databases, secrets)

  • Great for static/dynamic content that doesn't need interactivity

🧑‍💻 Client Components

  • Render on the client — shipped with JavaScript to the browser

  • Can use React hooks like useState, useEffect, etc.

  • Required for interactivity (forms, modals, animations, etc.)

📁 File Behavior in the App Router

In the new app/ directory of Next.js 13:

  • All components are Server Components by default

  • To make a component run on the client, you add the directive 'use client' at the top of the file

tsxCopyEdit// app/components/Counter.tsx
'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}

Without 'use client', this component would throw an error because useState is not supported in Server Components.

⚙️ How They Work Together

You can mix Server and Client Components, but with a few important rules:

  • Server Components can render Client Components

  • Client Components cannot import or render Server Components directly

Example:

tsxCopyEdit// Server Component (default)
import Counter from './Counter'; // A client component

export default async function Page() {
  const data = await fetchData(); // Server-side logic

  return (
    <div>
      <h1>{data.title}</h1>
      <Counter />
    </div>
  );
}

✅ This works.
❌ But trying to import a server-only function into a client component will throw an error.

🧩 Use Cases

Use This For…Server ComponentClient ComponentFetching data from DB/API✅🚫Static page content✅🚫User input / forms🚫✅Interactive UI (dropdowns, tabs)🚫✅Animations, client-side libraries🚫✅Authentication (server-side logic)✅🚫

⚠️ Common Pitfalls

  1. Forgetting 'use client'
    If you're using hooks like useState or useEffect, don't forget to declare 'use client' at the top of your file.

  2. Trying to fetch server data inside client components
    Fetch data on the server, then pass it as props to your client component.

  3. Performance hit from unnecessary client components
    Default to server components. Only use client components when interactivity is truly needed.

📊 Benefits of Server Components

  • ✅ Less client-side JavaScript

  • ✅ Faster load times

  • ✅ Simpler data fetching (no need for API routes)

  • ✅ More secure (sensitive logic stays on the server)

🔚 Conclusion

Next.js 13’s Client vs Server Component architecture encourages you to build faster and more scalable apps by keeping non-interactive UI on the server and using the client only when necessary.

By default, think server-first. Reach for 'use client' only when the UI demands interactivity.

Appreciate you dropping in! ッ

© 2025 Sam Yun. All Rights Reserved.

Appreciate you dropping in! ッ

© 2025 Sam Yun. All Rights Reserved.

Appreciate you dropping in! ッ

© 2025 Sam Yun. All Rights Reserved.

Home

Inbox

Feature Flag

Draft Mode

Share

Menu

Home

Inbox

Feature Flag

Draft Mode

Share

Menu

Create a free website with Framer, the website builder loved by startups, designers and agencies.