Next js

Module 6: Data Fetching (Client + Server) in Next.js 14 with TypeScript – SSR, ISR, SWR & Revalidation Explained

Fetching Data in App Router Using Server Components, SWR, and Revalidation

Next.js 14’s App Router gives you powerful ways to fetch and cache data in both Server and Client Components. In this module, you’ll learn how to:

  • Fetch data in page.tsx (Server Components)
  • Use fetch(), revalidate, and caching techniques
  • Perform client-side fetching using SWR and useEffect
  • Compare SSG, SSR, and ISR in real-world cases

🧩 Server-Side Data Fetching with Server Components

Server Components are default in App Router. You can use async directly in page.tsx or any server-only component.

🧪 Example: Fetching Posts in src/app/posts/page.tsx

// src/app/posts/page.tsx
type Post = {
  id: number;
  title: string;
};

async function getPosts(): Promise<Post[]> {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts", {
    next: { revalidate: 60 }, // ISR: revalidates every 60 seconds
  });
  return res.json();
}

export default async function PostsPage() {
  const posts = await getPosts();

  return (
    <div className="p-8">
      <h1 className="text-2xl font-bold mb-4">Server-Fetched Posts</h1>
      <ul className="space-y-2">
        {posts.slice(0, 5).map((post) => (
          <li key={post.id} className="p-2 border rounded">
            {post.title}
          </li>
        ))}
      </ul>
    </div>
  );
}

⚙️ Understanding revalidate, Cache, and Fetch Options

Next.js fetch() accepts powerful options:

Option Description
cache: "force-cache" Default. Uses static caching (SSG)
cache: "no-store" Always fetch fresh data (SSR)
next: { revalidate: n } ISR: Regenerate after n seconds

🧪 Example:

await fetch("https://api.com/data", {
  cache: "no-store" // SSR
});

await fetch("https://api.com/data", {
  next: { revalidate: 10 } // ISR (refresh every 10s)
});

🧪 Static Site Generation (SSG) with Server Components

By default, page.tsx will be statically generated unless you use no-store or dynamic params. This is perfect for blog pages, marketing content, or static dashboards.


🧠 Client-Side Data Fetching

When you need real-time updates, auth tokens, or user input-dependent queries, use client-side fetching.

Option 1: useEffect + fetch

"use client";
import { useEffect, useState } from "react";

export default function ClientPosts() {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((res) => res.json())
      .then(setPosts);
  }, []);

  return (
    <div className="p-8">
      <h2 className="text-xl font-bold mb-4">Client-Fetched Posts</h2>
      <ul className="space-y-2">
        {posts.slice(0, 5).map((post: any) => (
          <li key={post.id} className="border p-2 rounded">{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

Option 2: Using SWR for Smart Caching

Install SWR:

npm install swr
"use client";
import useSWR from "swr";

const fetcher = (url: string) => fetch(url).then((res) => res.json());

export default function SwrPosts() {
  const { data, error, isLoading } = useSWR(
    "https://jsonplaceholder.typicode.com/posts",
    fetcher
  );

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error loading posts</p>;

  return (
    <ul className="space-y-2 p-4">
      {data.slice(0, 5).map((post: any) => (
        <li key={post.id} className="border p-2 rounded">{post.title}</li>
      ))}
    </ul>
  );
}

⚖️ Comparing SSR vs SSG vs ISR

Strategy Syntax Use Case
SSG default, or fetch with force-cache Static pages (home, blog)
SSR fetch(..., { cache: "no-store" }) Authenticated or fresh data
ISR next: { revalidate: n } Semi-static content (news, listings)

🚫 Dynamic Rendering Caveats

If using SSR (no-store) or dynamic params, your route becomes dynamic. This disables static optimization and can affect performance and edge caching.

To enforce dynamic rendering:

export const dynamic = "force-dynamic"; // Optional

✅ Summary

You now know how to:

  • Use fetch() in Server Components with caching or revalidation
  • Use useEffect or SWR in Client Components for real-time data
  • Understand and apply SSR, SSG, and ISR strategies
  • Optimize performance using Next.js data-fetching best practices

🔜 Coming Up Next:

In Module 7, we’ll work with Forms and the latest Server Actions API, including validation with Zod, optimistic UI, and connecting to a database.

Would you like Module 6 in Markdown format or embedded HTML for your blog?

Leave a Reply

Your email address will not be published. Required fields are marked *