Data fetching in Next.js is one of the most important and exciting concepts developers encounter when building modern React applications. In Next.js, you can fetch content in multiple ways—but not all strategies are equal in performance, simplicity, or SEO value.
This article breaks down the difference between client-side data fetching (CSR) and server-side data fetching (SSR), shows code examples, explains how Next.js optimizes server fetching, and highlights why server components have become the new standard.
If you’re coming from plain React, you’re familiar with this pattern:
useEffect to fetch the dataHere’s what it typically looks like:
"use client";import { useEffect, useState } from "react";export default function Home() {const [albums, setAlbums] = useState([]);useEffect(() => {async function fetchAlbums() {const res = await fetch("https://jsonplaceholder.typicode.com/albums");const data = await res.json();setAlbums(data);}fetchAlbums();}, []);return (<div>{albums.map((album) => (<p key={album.id}>{album.title}</p>))}</div>);}
This works—but it’s not optimal.
useState, useEffect)There’s a better way.
Next.js lets you fetch data directly inside server components—no useEffect, no state, and no client-side logic required.
Here’s the cleaner version:
export default async function Home() {const res = await fetch("https://jsonplaceholder.typicode.com/albums");if (!res.ok) throw new Error("Failed to fetch");const albums = await res.json();return (<div>{albums.map((album) => (<p key={album.id}>{album.title}</p>))}</div>);}
useEffectuseStateIf you test server-side fetching locally, you might notice something odd: You need to refresh the browser to see new results.
This isn’t a bug.
Next.js now includes Server Components HMR Cache:
So if you update your fetch URL or API, refresh manually.
Here are the biggest benefits of choosing server-side data fetching:
SSR allows the page to load with the data already baked into the HTML. Users see content immediately. No waiting for JavaScript to run.
Search engines can read server-rendered HTML. Client-side fetching often means crawlers see… nothing.
If SEO matters, avoid CSR whenever possible.
No state. No effects. No unnecessary re-renders.
Server components keep data logic closer to the backend.
Next.js automatically ensures that:
If multiple components request the same data at the same time, only one API request is made.
Huge performance win.
API keys, private tokens, or sensitive logic stay on the server. Nothing leaks to the browser or user.
CSR often triggers multiple sequential requests. SSR can fetch everything in parallel before rendering.
You’ll learn parallel fetching later in the course—but trust me, it’s powerful.
Since server components run on the server:
…can be called directly, with no API routes in between.
Example:
import prisma from "@/lib/prisma";export default async function Posts() {const posts = await prisma.post.findMany();return <pre>{JSON.stringify(posts, null, 2)}</pre>;}
No API layer needed.
Just add:
"use client";
…and you’re back to traditional React.
CSR is still useful for:
…but it should NOT be your default for static or SEO-sensitive pages.
Try building both versions:
useEffectThen compare:
Initial page render
View page source (CSR will show nothing)
Disable JavaScript and reload
You’ll immediately understand why server components are the future of React + Next.js.
Next.js encourages a new mindset:
The server is your friend. Fetch there. Render there.
It’s cleaner, faster, more secure, and far better for SEO.
Client-side fetching still has its place—but it should no longer be your default.
If you’re new to these concepts or transitioning from React, don’t worry: everyone used CSR at first. With practice, server components and server-side data fetching will feel natural.
If you’d like, I can also turn this blog into:
✅ Prezi content slides ✅ A 4-section concise slide version ✅ Infographics ✅ Real-world examples comparing CSR and SSR ✅ Graphics or illustrations
Just tell me!