Skip to main content

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:

jsx
// 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:

jsx
// 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 in getStaticPaths
  • 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)
jsx
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:

jsx
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:

jsx
// 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:

jsx
// 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:

jsx
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:

jsx
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:

bash
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:

  1. Use getStaticProps to fetch data at build time
  2. Use getStaticPaths for dynamic routes
  3. Configure the fallback property based on your content update patterns
  4. Implement Incremental Static Regeneration with the revalidate property for data that changes occasionally

Additional Resources

Exercises

  1. Create a blog site that uses SSG to render article pages from markdown files
  2. Implement an e-commerce product page with ISR that revalidates every 10 minutes
  3. Build a documentation site with nested dynamic routes using getStaticPaths
  4. 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! :)