Clement Yuen
← Back to articles
Next.js·Intermediate

Next.js Server Components vs Client Components

8 Aug 2026 · 9 min read · Intermediate

  • #Next.js
  • #React
  • #Architecture

Share

In the App Router, components are Server Components by default. Client Components are an opt-in for interactivity. Mixing them well is the core skill.

Default to the server

Server Components can:

  • Read the filesystem / secrets / databases directly (on the server)
  • Keep heavy dependencies off the client bundle
  • Stream HTML without shipping their JS
Tsx
// app/blog/page.tsx — Server Component
import { getAllArticles } from '@/lib/posts';

export default function BlogPage() {
  const articles = getAllArticles();
  return <ul>{articles.map((a) => <li key={a.slug}>{a.title}</li>)}</ul>;
}

When you need "use client"

Mark a Client Component when you need:

  • useState / useEffect / browser APIs
  • Event handlers (onClick, onChange)
  • Certain third-party widgets that assume the DOM
Tsx
'use client';

import { useState } from 'react';

export function SearchBox() {
  const [query, setQuery] = useState('');
  return (
    <input
      value={query}
      onChange={(e) => setQuery(e.target.value)}
      placeholder="Search articles..."
    />
  );
}

Composition pattern

Keep Client Components small and leafy. Pass serializable props from the server:

Tsx
// Server
import { BlogListing } from '@/components/blog-listing';
import { getAllArticles } from '@/lib/posts';

export default function Page() {
  return <BlogListing articles={getAllArticles()} />;
}

Do not wrap an entire page in "use client" just because one filter chip needs state.

Shared boundaries

You can import a Client Component into a Server Component. You cannot import a Server Component into a Client Component and expect it to stay server-only—pass it as children instead:

Tsx
'use client';

export function Shell({ children }: { children: React.ReactNode }) {
  return <div className="shell">{children}</div>;
}

Conclusion

Ask: Does this need the browser? If not, keep it on the server. If yes, isolate the interactive island and leave data loading above it.

Related Articles