Next.js Static Site Generation
Static Site Generation (SSG) is one of the core rendering strategies in Next.js that can significantly improve your application's performance. With SSG, pages are generated at build time rather than on each request, resulting in faster page loads and better user experience.
Introduction to Static Site Generation
Static Site Generation represents a fundamental shift in how web content is delivered. Instead of generating HTML for each user request (as in server-side rendering), SSG pre-renders pages during the build process, creating static HTML files that can be quickly served to users.
Key Benefits of Static Site Generation
- Improved Performance: Pages load faster because they're pre-rendered and can be cached at the edge
- Better SEO: Search engines can easily crawl fully rendered content
- Enhanced Security: Reduced attack surface with fewer server-side processes
- Lower Server Costs: Decreased server load since pages don't need to be generated for each request
- Reliable: Works without an active backend connection once deployed
How Static Site Generation Works in Next.js
In Next.js, you can implement Static Site Generation through the getStaticProps
and getStaticPaths
functions.
Using getStaticProps
The getStaticProps
function runs at build time, fetching data and passing it to the page as props. Here's a basic example:
// pages/blog.js
export default function Blog({ posts }) {
return (
<div>
<h1>Blog Posts</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
// This function runs at build time
export async function getStaticProps() {
// Fetch data from an API or database
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
props: {
posts, // Will be passed to the page component as props
},
};
}
When you build your Next.js application, the getStaticProps
function will execute, fetch the blog posts, and inject them as props into your page component. The HTML is then generated and ready to be served to users.
Dynamic Routes with getStaticPaths
For pages that use dynamic routes, you'll need to specify which paths to pre-render using getStaticPaths
:
// pages/posts/[id].js
export default function Post({ post }) {
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
);
}
// This function determines which paths will be pre-rendered
export async function getStaticPaths() {
// Fetch list of all possible post IDs
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
// Generate paths for each post
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
}));
return {
paths,
fallback: false, // 404 for paths not returned by getStaticPaths
};
}
export async function getStaticProps({ params }) {
// Fetch data for a single post
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return {
props: {
post,
},
};
}
In this example, Next.js will pre-render all paths returned by getStaticPaths
during the build process.
Configuration Options for Static Generation
The fallback
Property
The fallback
property in getStaticPaths
provides options for handling routes that weren't pre-rendered at build time:
false
: Returns a 404 page for any paths not defined ingetStaticPaths
true
: Generates the page on-demand when requested (shows a loading state)'blocking'
: Generates the page on-demand without showing a loading state (similar to server-side rendering)
export async function getStaticPaths() {
// Get only the most popular posts for pre-rendering
const res = await fetch('https://api.example.com/popular-posts');
const popularPosts = await res.json();
const paths = popularPosts.map((post) => ({
params: { id: post.id.toString() },
}));
return {
paths,
fallback: true, // Enable on-demand generation for other posts
};
}
Incremental Static Regeneration (ISR)
Next.js enhances SSG with Incremental Static Regeneration, allowing you to update static pages after deployment without rebuilding the entire site:
export async function getStaticProps() {
const res = await fetch('https://api.example.com/products');
const products = await res.json();
return {
props: {
products,
},
revalidate: 60, // Regenerate page at most once every 60 seconds
};
}
The revalidate
property specifies how often (in seconds) the page should be regenerated in the background when requests come in.
Real-World Use Cases
E-commerce Product Catalog
An e-commerce website can benefit from SSG for product listing pages that don't change frequently:
// pages/products/category/[category].js
export default function CategoryPage({ products, category }) {
return (
<div>
<h1>{category} Products</h1>
<div className="product-grid">
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
</div>
);
}
export async function getStaticPaths() {
// Get all product categories
const categories = await fetchCategories();
const paths = categories.map((category) => ({
params: { category: category.slug },
}));
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
// Fetch products for this category
const products = await fetchProductsByCategory(params.category);
return {
props: {
products,
category: params.category,
},
// Regenerate every hour to reflect inventory changes
revalidate: 3600,
};
}
Marketing Website
Marketing websites with relatively stable content are perfect candidates for SSG:
// pages/about.js
export default function AboutPage({ team, companyInfo }) {
return (
<div className="about-page">
<h1>About {companyInfo.name}</h1>
<div className="company-mission">{companyInfo.mission}</div>
<h2>Our Team</h2>
<div className="team-grid">
{team.map((member) => (
<TeamMember key={member.id} member={member} />
))}
</div>
</div>
);
}
export async function getStaticProps() {
// This could come from a CMS
const companyInfo = await fetchCompanyInfo();
const team = await fetchTeamMembers();
return {
props: {
companyInfo,
team,
},
// Content doesn't change often, but when it does, we want it updated
revalidate: 86400, // 24 hours
};
}
Performance Optimization Tips
Optimize Images
Use Next.js built-in Image component for optimized image loading:
import Image from 'next/image';
function ProductImage({ product }) {
return (
<Image
src={product.imageUrl}
alt={product.name}
width={500}
height={300}
priority={false}
loading="lazy"
/>
);
}
Preload Critical Data
For pages that require multiple data sources, use Promise.all
to fetch them in parallel:
export async function getStaticProps() {
const [productsRes, categoriesRes, featuredRes] = await Promise.all([
fetch('https://api.example.com/products'),
fetch('https://api.example.com/categories'),
fetch('https://api.example.com/featured')
]);
const [products, categories, featured] = await Promise.all([
productsRes.json(),
categoriesRes.json(),
featuredRes.json()
]);
return {
props: {
products,
categories,
featured
}
};
}
Analyze Build Output
Next.js provides build analytics to help you understand which pages are statically generated:
npm run build
This will display information about each generated page, including its size and build time.
When to Use Static Generation
Static Generation is best suited for:
- Marketing pages
- Blog posts
- E-commerce product listings
- Documentation
- Landing pages
- Portfolio websites
It might not be the best choice when:
- Content changes very frequently (per user or per second)
- Pages are highly personalized for each user
- Content depends on user-specific factors like cookies or authentication
Summary
Static Site Generation in Next.js offers tremendous performance benefits by pre-rendering pages at build time. By leveraging getStaticProps
and getStaticPaths
, you can create lightning-fast websites that are SEO-friendly and cost-effective to host. Combined with Incremental Static Regeneration, you get the best of both worlds: the performance of static sites with the ability to update content without full rebuilds.
Remember these key takeaways:
- Use
getStaticProps
to fetch data at build time - Use
getStaticPaths
for dynamic routes - Configure the
fallback
property based on your content update patterns - Implement Incremental Static Regeneration with the
revalidate
property for data that changes occasionally
Additional Resources
- Next.js Official Documentation on Static Generation
- Learn about ISR in detail
- Next.js Examples Repository
Exercises
- Create a blog site that uses SSG to render article pages from markdown files
- Implement an e-commerce product page with ISR that revalidates every 10 minutes
- Build a documentation site with nested dynamic routes using
getStaticPaths
- Compare the performance of a statically generated page versus a server-rendered version of the same page
By mastering Static Site Generation in Next.js, you'll be able to create high-performance applications that provide excellent user experiences while minimizing server costs and maintenance overhead.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)