Next js

CSR Static Site Rendering, SSR Server Side Rendering, ISR Incremental Static Regeneration

In Next.js, Static Rendering and Dynamic Rendering determine when HTML is generated.

OptionGenerated WhenCachedUse Case
Default StaticBuild TimeYesAbout, Contact
dynamic = "force-static"Build TimeYesLanding Pages
next: { revalidate: 60 }Every 60 secYesJob Listings, Blogs
cache: "no-store"Every RequestNoDashboard, Admin
dynamic = "force-dynamic"Every RequestNoProfile, Cart, Orders
FeatureStatic RenderingDynamic Rendering
HTML GeneratedAt build timeOn every request
SpeedVery fastSlower than static
Server LoadLowHigher
SEOExcellentExcellent
Best ForBlog, Landing Page, Job ListingsUser Dashboard, Live Data
Data FreshnessMay become outdatedAlways fresh

In Next.js App Router, there are 4 major rendering/caching options you should know.


1. Static Rendering (Default)

Page is generated once and cached.

async function getJobs() {
const response = await fetch(
"https://api.example.com/jobs"
);

return response.json();
}

export default async function Page() {
const jobs = await getJobs();

return <h1>{jobs.length}</h1>;
}

What happens?

next build

Fetch Data

Generate HTML

Store in cache

Serve same HTML to everyone

Best For

  • About Us
  • Contact Us
  • Service Pages
  • SEO Landing Pages

2. Force Static

Even if Next.js suspects dynamic behavior, force it to be static.

export const dynamic = "force-static";

export default function Page() {
return <h1>Static Page</h1>;
}

What happens?

Build Time Rendering
Only Once

Best For

/about
/privacy-policy
/terms

3. Dynamic Rendering (SSR)

Generate page on every request.

export const dynamic = "force-dynamic";

async function getJobs() {
const response = await fetch(
"https://api.example.com/jobs",
{
cache: "no-store"
}
);

return response.json();
}

export default async function Page() {
const jobs = await getJobs();

return (
<div>
{jobs.map((job:any) => (
<p key={job.id}>{job.title}</p>
))}
</div>
);
}

What happens?

User Request

Run API

Generate HTML

Return HTML

Every request:

Fresh Data
Fresh HTML

Best For

/dashboard
/profile
/admin
/cart
/orders

4. cache: “no-store”

Forces fresh fetch every time.

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

Equivalent behavior:

export const dynamic = "force-dynamic";

Meaning

Don't cache
Always fetch latest data

5. ISR (Incremental Static Regeneration)

Most useful feature.

const response = await fetch(
"https://api.example.com/jobs",
{
next: {
revalidate: 60
}
}
);

Meaning

Cache page
After 60 seconds
Regenerate in background

Flow

First User

Generate HTML

Cache

Next 60 seconds

Serve Cache

After 60 seconds

Generate New Version

Example Timeline

next: {
revalidate: 60
}
10:00 First User
Generate Page

10:01
Serve Cached Page

10:02
Serve Cached Page

10:03
Serve Cached Page

10:04
Serve Cached Page

10:05
60 seconds completed
Regenerate Page

Job Portal Example

Home Page

export const dynamic = "force-static";

Reason:

SEO
Fast
Rarely changes

Job Category

const response = await fetch(
"https://api.cybotrix.com/categories",
{
next: {
revalidate: 300
}
}
);

Reason:

Jobs update occasionally
Need SEO
Need speed

Job Details

const response = await fetch(
"https://api.cybotrix.com/job/react-developer",
{
next: {
revalidate: 60
}
}
);

Reason:

Job status may change
SEO required

Candidate Dashboard

export const dynamic = "force-dynamic";

or

const response = await fetch(
"/api/dashboard",
{
cache: "no-store"
}
);

Reason:

User-specific data
Always fresh

Summary Table

OptionGenerated WhenCachedUse Case
Default StaticBuild TimeYesAbout, Contact
dynamic = "force-static"Build TimeYesLanding Pages
next: { revalidate: 60 }Every 60 secYesJob Listings, Blogs
cache: "no-store"Every RequestNoDashboard, Admin
dynamic = "force-dynamic"Every RequestNoProfile, Cart, Orders

Interview Answer (Short)

Static Rendering:
HTML is generated at build time and reused for all users.

Dynamic Rendering:
HTML is generated on every request and always shows fresh data.

ISR:
A hybrid approach where HTML is cached and automatically regenerated after a specified interval using revalidate.

For your recruitment portal, the usual pattern is:

Home Page        → force-static
Job Categories → revalidate: 300
Job Details → revalidate: 60
Blog → revalidate: 1800
Candidate Panel → force-dynamic
Admin Panel → force-dynamic