From nextjs-toolkit
Advises optimal Next.js rendering strategies (SSG, SSR, ISR, CSR) based on content type, update frequency, SEO, and performance for pages and data fetching.
How this skill is triggered — by the user, by Claude, or both
Slash command
/nextjs-toolkit:ssr-ssg-advisorThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Choose the optimal rendering strategy for Next.js pages based on requirements.
Choose the optimal rendering strategy for Next.js pages based on requirements.
Decision criteria:
Ask these questions:
Static Site Generation (SSG):
// pages/products/[id].tsx
export async function getStaticProps({ params }) {
const product = await fetchProduct(params.id);
return {
props: { product },
// Optional: revalidate for ISR
// revalidate: 60, // seconds
};
}
export async function getStaticPaths() {
const products = await fetchAllProducts();
return {
paths: products.map(p => ({ params: { id: p.id } })),
fallback: 'blocking', // or false, or true
};
}
When to use SSG:
Server-Side Rendering (SSR):
// pages/dashboard.tsx
export async function getServerSideProps(context) {
const session = await getSession(context);
const data = await fetchUserData(session.userId);
return {
props: { data },
};
}
When to use SSR:
Incremental Static Regeneration (ISR):
// pages/blog/[slug].tsx
export async function getStaticProps({ params }) {
const post = await fetchPost(params.slug);
return {
props: { post },
revalidate: 60, // Regenerate every 60 seconds
};
}
When to use ISR:
Client-Side Rendering (CSR):
'use client'; // App Router
import { useEffect, useState } from 'react';
function Dashboard() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/user-data')
.then(res => res.json())
.then(setData);
}, []);
return <div>{data ? <Content data={data} /> : <Loading />}</div>;
}
When to use CSR:
App Router (Next.js 13+):
// app/products/page.tsx
async function ProductsPage() {
// SSG: cached by default
const products = await fetch('https://api.example.com/products');
// ISR: revalidate periodically
const products = await fetch('https://api.example.com/products', {
next: { revalidate: 3600 } // 1 hour
});
// SSR: no caching
const products = await fetch('https://api.example.com/products', {
cache: 'no-store'
});
return <ProductList products={products} />;
}
Pages Router:
// getStaticProps: SSG/ISR
// getServerSideProps: SSR
// useEffect + fetch: CSR
On-demand revalidation:
// app/api/revalidate/route.ts
import { revalidatePath, revalidateTag } from 'next/cache';
export async function POST(request) {
const path = request.nextUrl.searchParams.get('path');
if (path) {
revalidatePath(path);
return Response.json({ revalidated: true });
}
return Response.json({ revalidated: false });
}
Tagged caching:
// Fetch with tags
const data = await fetch('https://api.example.com/products', {
next: { tags: ['products'] }
});
// Revalidate by tag
revalidateTag('products');
getStaticPaths fallback options:
export async function getStaticPaths() {
return {
paths: [...],
fallback: false, // 404 for non-pre-rendered paths
// fallback: true, // Generate on-demand, show loading
// fallback: 'blocking', // Generate on-demand, wait for page
};
}
// Mix strategies in same app
// - SSG for marketing pages
// - ISR for blog posts
// - SSR for user dashboard
// - CSR for interactive features
// app/layout.tsx (SSG)
export default function RootLayout({ children }) {
return <html><body>{children}</body></html>;
}
// app/blog/[slug]/page.tsx (ISR)
async function BlogPost({ params }) {
const post = await fetch(`/api/posts/${params.slug}`, {
next: { revalidate: 60 }
});
return <Article post={post} />;
}
// app/dashboard/page.tsx (SSR)
async function Dashboard() {
const data = await fetch('/api/user', { cache: 'no-store' });
return <DashboardContent data={data} />;
}
// Show stale data immediately, revalidate in background
export async function getStaticProps() {
const data = await fetchData();
return {
props: { data },
revalidate: 1, // Revalidate every second
};
}
// Different rendering based on route
export async function getServerSideProps(context) {
const { preview } = context;
if (preview) {
// SSR for preview mode
const data = await fetchDraftContent();
return { props: { data, preview: true } };
}
// Redirect to SSG version
return {
redirect: {
destination: '/static-version',
permanent: false,
},
};
}
| Requirement | SSG | ISR | SSR | CSR |
|---|---|---|---|---|
| SEO Critical | ✅ | ✅ | ✅ | ❌ |
| Fast TTFB | ✅ | ✅ | ❌ | ❌ |
| Fresh Data | ❌ | ⚠️ | ✅ | ✅ |
| Personalized | ❌ | ❌ | ✅ | ✅ |
| Large Scale | ⚠️ | ✅ | ✅ | ✅ |
| Build Time | ❌ | ✅ | ✅ | ✅ |
✅ = Excellent, ⚠️ = Acceptable, ❌ = Poor
SSG:
ISR:
SSR:
CSR:
Build taking too long:
Stale data showing:
High server costs:
SEO issues:
npx claudepluginhub p/armanzeroeight-nextjs-toolkit-plugins-nextjs-toolkitPre-renders Next.js pages at build time or on a schedule using SSG, generateStaticParams, and ISR for reduced server costs and faster CDN delivery.
Guides selection and optimization of rendering strategies (SSG, SSR, ISR, CSR, dynamic rendering) for SEO and crawler visibility. Helps ensure page content and metadata load without JavaScript execution.
Senior Next.js 14+ specialist for App Router, server components, server actions, data fetching, SEO with generateMetadata, streaming SSR, loading/error boundaries, and Vercel deployment.