// app/page.tsx - This is a Server Component by default!
async function Page() {
// Can fetch data directly - no useEffect needed
const data = await fetch('https://api.example.com/data');
const posts = await data.json();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
export default Page;| Server Components | Client Components |
|---|---|
| Fetch data | onClick, onChange handlers |
| Access backend resources | useState, useEffect |
| Keep secrets on server | Browser APIs (localStorage) |
| Large dependencies | Interactivity |
'use client'; // Add this directive at the top
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}// app/page.tsx (Server Component)
import { Counter } from './Counter'; // Client Component
async function Page() {
const data = await fetchData(); // Server-side fetch
return (
<div>
<h1>{data.title}</h1> {/* Server rendered */}
<Counter /> {/* Client interactive */}
</div>
);
}- Zero JavaScript for static content
- Direct database/API access
- Secrets stay on server
- Smaller bundle size
- Better SEO
Learned: December 20, 2025 Tags: Next.js, React Server Components, App Router
