Next.js Lesson 5: Server Components
Server Components are the game-changer in Next.js 13+. They run on the server — no JavaScript sent to the browser, direct database access, faster pages.
Server Component (default in App Router)
// By default, ALL components in app/ are Server Components
// No "use client" directive = Server Component
// app/page.tsx — runs on SERVER
async function BlogPosts() {
// Direct database query (no API needed!)
const posts = await db.query("SELECT * FROM posts");
// OR fetch from external API
const data = await fetch("https://api.example.com/posts");
const posts = await data.json();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
export default BlogPosts;
What Server Components CAN and CANNOT do
// ✅ Server Components CAN:
// - async/await directly
// - Query databases
// - Read files
// - Access environment variables (private ones too)
// - Import server-only packages
// ❌ Server Components CANNOT:
// - Use useState, useEffect, useRef
// - Add onClick, onChange event handlers
// - Use browser APIs (localStorage, window)
// - Use React context
Streaming with Suspense
import { Suspense } from "react";
export default function Page() {
return (
<div>
<h1>Dashboard</h1> {/* renders immediately */}
{/* Streams in when ready */}
<Suspense fallback={<p>Loading stats...</p>}>
<SlowStats /> {/* takes 2 seconds */}
</Suspense>
<Suspense fallback={<p>Loading feed...</p>}>
<NewsFeed /> {/* takes 3 seconds */}
</Suspense>
</div>
);
}
🏋️ Practice Task
Build a Server Component that fetches posts from https://jsonplaceholder.typicode.com/posts (limit 5) with direct async/await in the component. Show title and body. Add a Suspense wrapper in the parent page with a skeleton loading state.
💡 Hint: async function Posts() { const posts = await fetch(“…”).then(r=>r.json()); return
- …
; } Just make it async, no useEffect!