ā¤ Like
šŸ”– Save
šŸ”— Share
Eric Hu
Eric Hu

Next.js Rendering

@thedevspaceio

ā–² Next.js Rendering Strategies

Next.js supports multiple rendering strategies. Static is fastest. Dynamic is freshest. ISR gives you both.

Here's how to pick the right strategy:

āœ… Static rendering (default) āœ… Dynamic rendering āœ… Incremental Static Regeneration (ISR) āœ… Streaming

#nextjs #react #ssr #ssg #streaming #webdev #frontend #coding #tips


Next.js renders pages in different ways depending on the data and APIs you use. Choosing the right strategy affects performance and freshness.

StrategyWhen it runsBest for
Static (SSG)Build timeContent that rarely changes
Dynamic (SSR)Every requestPersonalized or real-time data
ISRBuild + revalidateContent that changes occasionally
StreamingProgressivelySlow data with fast shell

Static rendering (default)

Pages are rendered at build time and served from a CDN.

tsx
// Rendered at build time by default
export default async function Blog() {
  const posts = await getPosts();
  return <PostList posts={posts} />;
}

A page is static when it uses no dynamic APIs or uncached data.


Dynamic rendering

Pages render on every request. Triggered by dynamic APIs or uncached fetches.

Dynamic APIs force dynamic rendering:

tsx
import { cookies, headers } from "next/headers";
 
export default async function Profile() {
  const cookieStore = await cookies();
  const theme = cookieStore.get("theme");
}

Uncached fetch also forces dynamic rendering:

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

Force dynamic rendering with a route segment config:

tsx
export const dynamic = "force-dynamic";

Incremental Static Regeneration (ISR)

Update static content without rebuilding the entire site. Pre-render pages at build time, then revalidate them in the background.


app/blog/[id]/page.tsx

tsx
export const revalidate = 60; // revalidate at most every 60 seconds
 
export async function generateStaticParams() {
  const posts = await fetch("https://api.example.com/posts").then((res) =>
    res.json(),
  );
 
  return posts.map((post) => ({ id: String(post.id) }));
}
 
export default async function Page({ params }) {
  const { id } = await params;
  const post = await fetch(`https://api.example.com/posts/${id}`).then((res) =>
    res.json(),
  );
 
  return <Post post={post} />;
}

How it works:

  1. generateStaticParams returns the pages to pre-render at build time.
  2. Requests to those pages are served instantly from cache.
  3. After revalidate seconds, the next request still gets the stale page, and Next.js regenerates it in the background.
  4. Once regenerated, subsequent requests get the fresh version.
  5. Paths not in generateStaticParams are generated on demand at first request (unless dynamicParams = false).

On-demand revalidation

Invalidate the cache from a server action or route handler instead of waiting for the interval.

tsx
"use server";
 
import { revalidatePath, revalidateTag } from "next/cache";
 
export async function createPost() {
  revalidatePath("/posts"); // invalidate an entire route
  revalidateTag("posts", "max"); // or invalidate tagged fetches
}

Tag individual fetches for granular control.

tsx
fetch("https://api.example.com/posts", { next: { tags: ["posts"] } });

Regeneration happens on the next request after invalidation, not immediately.


Streaming

Render the page shell instantly and stream in slow parts with Suspense.

tsx
import { Suspense } from "react";
 
export default function Dashboard() {
  return (
    <div>
      <Header /> {/* renders immediately */}
      <Suspense fallback={<Skeleton />}>
        <SlowChart /> {/* streams in when ready */}
      </Suspense>
    </div>
  );
}

loading.tsx wraps the page in Suspense automatically.

Full-Stack AI Developer Roadmap

From HTML & CSS to working with AI models, all in one structured roadmap.

@thedevspaceio
www.thedevspace.io