
Introduction to Static Site Generation in Next.js Applications
Static Site Generators (SSG) have transformed web development over the past two decades, starting as niche tools for small, fast-loading sites and evolving into essential frameworks for high-performance applications. Early adopters, particularly Movable Type in 2001 and Jekyll in 2008 pioneered this approach, generating pre-rendered HTML that bypassed the need for server-side rendering on every page load.
The use of SSGs surged around 2015 with the advent of the Jamstack architecture, promoting a static-first approach to web development. JavaScript frameworks such as Next.js contributed to SSG’s popularity by making it accessible for modern React-based applications.
Since introducing static site generation capabilities in version 9.3 (released in March 2020), Nextjs has become a leading choice for static site generation. The framework combines the speed and SEO benefits of SSG with a powerful ecosystem, enabling developers to create fast, SEO-friendly websites without compromising on user experience.
In this guide, we’ll explore how to use Next js static site generation to build and deploy high-performance, secure, and scalable web apps that elevate the user experience.
What are Static Site Generators (SSG)?
A Static Site Generator (SSG) is a tool that generates a complete static HTML website based on raw data and templates. It’s known for delivering super-fast websites because it generates pages at build time.
Next.js is considered a great option for SSG because it not only generates static pages but also provides benefits such as super-fast performance, up-to-date security, and improved user experience without compromising on SEO or the quality of the user interface.
Why USE SSG?
🚀 STATIC = FAST 🚀
Static Site Generator is extremely fast. Once loaded, they prefetch resources for other pages so navigating the site feels instantaneous
💎 STATIC = SAFE 💎
With a static site generator, you will just publish static files, which means there is no direct connection to the database, dependencies, user’s data or other sensitive information.
😎 STATIC = ENHANCED USER EXPERIENCE 😎
Simply because clicking and walking through your static website feels like a walk in a park on a sunny day with no unexpected turns, stairs, or dead ends.
Static Pages also got kind of a new brand name on the market, which is Jamstack.
What is Next.js?
Next.js is a full-stack React framework for building high-performance web applications with integrated front-end and back-end capabilities. It supports multiple rendering methods: Server-Side Rendering (SSR), Static Site Generation (SSG), and Incremental Static Regeneration (ISR), enabling high flexibility and performance for a variety of content needs. Next js applies pre-rendering by default, delivering SEO-optimized HTML that is fast-loading and optimized for user experience.
Additionally, the framework includes an intuitive file-based routing system that automatically creates routes based on the structure of the pages directory, making navigation straightforward and eliminating complex setup
With the recent addition of Partial Prerendering (PPR), Next.js allows developers can now combine static and dynamic content on the same page, which enhances load times while maintaining dynamic content for specific sections.
If you want to learn more about Next.js, be sure to watch our video:
As the most widely used React framework and now recommended by the React team as the go-to option for new projects, Next.js is well-regarded for building fast, SEO-friendly, and scalable applications effortlessly.
In this post, we will be taking a look at the static page export functionality and how we use static generation with Next.js
Let’s go!
Creating and Configuring a Next.js App for Static Site Generation
We will start by creating a new Next app. To do that simply run the command:
yarn create next-app
# or if you are using npm
npx create-next-appFollow the instructions and select options that suit you.

Now, let’s take a look at our project structure:

- src/app/page – this is the homepage of our application (more about routing here).
- src/app/layout – the layout file that will wrap all of our pages. Our header and footer should be here.
- public – we can put all our static assets in this directory.
Let’s change the project configuration to reflect what we want to achieve in this project. Go to next.config.ts and add an output option:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
output: "export",
};
export default nextConfig;Now we can test our configuration, run the build command:
yarn run build
# or if you are using npm
npm run build
Next should create an out directory at the root of our project with all the static HTML files and assets ready to host.

We can change the out directory by adding distDir to next.config.ts like this:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
output: "export",
distDir: "dist",
};
export default nextConfig;Not sure if Next.js is for you?
Adding Content to Page
Let’s head to src/app/page.ts file and change its content to something like this:
export default function Home() {
return (
<div className="font-sans grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
<main className="flex flex-col gap-[32px] items-center sm:items-start">
<h1>Hello world</h1>
</main>
<footer>
<p>Last build time: {new Date().toLocaleString()}</p>
</footer>
</div>
);
}
And start our app by running command:
yarn run dev
# or if you are using npm
npm run devNow you should be able to access http://localhost:3000 and see our page content.
We’ve added Last build time date, which will be evaluated at the build time. You’ll see that date changes every refresh, this will not be the case when we build our app because code is executed only once when the app is building.
Try it by yourself – build the app and see if the date is persistent on the out/index.html file.
yarn build
# or if you are using npm
npm run build As a result, all of our code will be executed only during the build phase now.
Adding Data Source and “Dynamic” Pages
We already know that our data will be static. But how to generate pages based on API statically?
To demonstrate, let’s use a public API. In a typical scenario, you should use your API or CMS system to fetch data at this step.
To start, add a new page with a listing of posts fetched from the external API app/posts/page.tsx.
Now we can create a method that will fetch all the posts.
async function fetchAllPosts(): Promise<Post[]> {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!res.ok) {
throw new Error('Failed to fetch posts');
}
return res.json();
}Use it in our page to render a list:
import Link from "next/link";
interface Post {
userId: number;
id: number;
title: string;
body: string;
}
async function fetchAllPosts(): Promise<Post[]> {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!res.ok) {
throw new Error('Failed to fetch posts');
}
return res.json();
}
export default async function PostsPage() {
const posts = await fetchAllPosts();
return (
<main className="min-h-screen p-8 max-w-4xl mx-auto flex flex-col gap-4">
{posts.map((post) => (
<Link href={`/posts/${post.id}`} key={post.id}>
<article className="flex flex-col space-y-6 border-b pb-4" key={post.id}>
<h6 className="text-4xl font-bold mb-2">{post.title}</h6>
<div className="text-sm text-gray-600">
Post ID: {post.id} | Author ID: {post.userId}
</div>
</article>
</Link>
))}
</main>
);
}Now if we will build an app we will have a list of posts on the /posts page, however it will be build once just once. Even if someone adds a new post or modifies one of the items, the old data is still there. To update, we will need to rebuild our app.
Let’s go and implement the detail pages.
Creating Pages and Fetching Data in Next js
Read more about the dynamic routing here.
First, we have to add a dynamic route to our app, which we can do that by creating a file with square brackets in its name: app/posts/[id]/page.tsx .
When we are building our pages statically, Next.js requires to export a function called generateStaticParams from the page. It’s beause the framework needs to know all the page URLs and their params at the build time.
Once we have fetched the list of posts at our homepage, we have to do the same in our generateStaticParams to generate URLs.
// Generate static params for all posts
export async function generateStaticParams() {
const posts = await fetchAllPosts();
return posts.map((post) => ({
id: post.id.toString(),
}));
}Then we need to declare a body of our page and fetch more details inside:
interface Post {
userId: number;
id: number;
title: string;
body: string;
}
interface PageProps {
params: Promise<{
id: string;
}>;
}
async function fetchPost(id: string): Promise<Post> {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
if (!res.ok) {
throw new Error('Failed to fetch post');
}
return res.json();
}
async function fetchAllPosts(): Promise<Post[]> {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!res.ok) {
throw new Error('Failed to fetch posts');
}
return res.json();
}
// Generate static params for all posts
export async function generateStaticParams() {
const posts = await fetchAllPosts();
return posts.map((post) => ({
id: post.id.toString(),
}));
}
export default async function PostPage({ params }: PageProps) {
const { id } = await params;
const post = await fetchPost(id);
return (
<main className="min-h-screen p-8 max-w-4xl mx-auto">
<article className="space-y-6">
<header className="border-b pb-4">
<h1 className="text-4xl font-bold mb-2">{post.title}</h1>
<div className="text-sm text-gray-600">
Post ID: {post.id} | Author ID: {post.userId}
</div>
</header>
<div className="prose prose-lg">
<p className="text-gray-800 leading-relaxed whitespace-pre-line">
{post.body}
</p>
</div>
</article>
</main>
);
}If you go to url like /posts/2 or any matching id, you should get a page with the content.
Let’s build our app and see if it works:
![Terminal screenshot showing a Next.js build summary. It lists completed steps, file sizes, page routes like /posts and /posts/[id], shared JavaScript files, and highlights Next.js static site generation with static and SSG rendering options explained.](https://pagepro.co/blog/wp-content/uploads/2024/10/nextjs-static-ssg-build-multiple-pages.png)
Once the build completes, you’ll notice Next.js created hundreds of pages. That means our setup is working as expected.
The legend at the bottom shows which routes are fully static and which used SSG. Another quick way to confirm is to check the out folder and see the generated HTML files.

Revalidating the Static Data
Since output: "export" is enabled in next.config.ts, the project builds as a fully static site. Using generateStaticParams(), Next.js pre-renders all 100 post pages at build time and saves them as HTML inside the /out directory. This gives you:
- A fully static site that can be hosted anywhere (Netlify, Vercel, S3, GitHub Pages, etc.)
- No server required
- Instant page loads
- No additional rebuilding and redeploying when content is changed
If you want pages to refresh automatically instead of rebuilding the entire project each time content changes, switch to ISR. Remove output: "export" from next.config.ts, since ISR requires a server environment. Then add a revalidate value to the pages you want to update on a set interval.
export const revalidate = 86400; // Revalidate every 24 hours (in seconds)
You can also extend this setup to support full revalidation.
What This Gives You
- Pages still build as static files initially
- After your chosen interval (for example, 24 hours), a page is refreshed on the next request
- No full rebuild needed when content changes
- Requires a Node.js environment (Vercel or any host that supports Next.js server functions)
Things to Keep inMmind
- ISR: Content updates automatically, but you need server support
- Static export: Works on any static host, but you must rebuild to update content
Pick the approach that fits your hosting setup and how often your content changes
Next.js vs React
We’ve also made a comparison between Next.js and React:
Conclusion
If you want to create an outstanding web project, using Next.js for Static Site Generation (SSG) delivers you a powerful way to build websites that are fast, secure, and SEO-friendly, without sacrificing flexibility.
With easy setup commands, seamless routing, and features such as generateStaticParams, Next.js offers a straightforward approach to creating static pages. The framework’s ability to integrate external data sources using tools such as Apollo Client further enhances its utility for creating dynamic, data-rich sites.
Lastly, with Partial Pre-render (PPR), Incremental Static Regeneration (ISR), and server-side capabilities, Next.js combines the best of static and dynamic web content management, allowing developers to create pages that load instantly yet stay updated with minimal overhead.
FAQ
SSG in Next.js works by fetching data and pre-rendering pages at build time, generating static HTML files that can be served immediately.
When you run the build command, Next.js executes your page code once, retrieves any data from APIs or CMSs, and saves the final HTML inside the /out directory. Each page is then delivered as a pre-built file, so there’s no need for a server to render content on request.
As a result, your site becomes faster, more secure, and easier to host. Dynamic content updates can be done without a full rebuild through Incremental Static Regeneration (ISR). It regenerates pages automatically after a set interval.
With SSG your Next.js website runs faster, is safer, and easier to maintain.
Since pages are built ahead of time and served as static HTML, they load at once and can be cached globally on CDNs. With no need for a server to render content, there’s also less risk of downtime or security issues.
SSG is great for SEO too. Search engines can index pre-rendered content easily, increasing your page rank. And with Incremental Static Regeneration (ISR), you can still update content automatically without having to rebuild the entire site.
Yes. Next.js can pull data from APIs, databases, or CMSs like Sanity using the built-in fetch() function or async methods during Static Site Generation (SSG).
The data is fetched once at build time and pre-rendered into static HTML. To keep pages fresh without full rebuilds, you can enable Incremental Static Regeneration (ISR) with a revalidate interval.
Next.js is a popular choice for static site generation because it offers exceptional speed through static generation and optimized code, which reduces bounce rates and improves SEO rankings.
Additionally, its rich ecosystem, supported by Vercel, makes it a future-proof and scalable solution for web development.
Compared to other frameworks, Next.js is very flexible. It supports multiple rendering methods like Static Site Generation (SSG), Server-Side Rendering (SSR), Incremental Static Regeneration (ISR), and Client-Side Rendering.
Astro focuses on content-driven sites and is easy to use even without experience in frameworks like React or Vue.
Eleventy is framework-agnostic, lightweight, and easy to set up for projects of any size.
Are you ready to start your new Next.js project?
Read more
Great Examples of Next js Websites
How to Rank Higher on Google with Next js
What Is Next Js And Why Should You Use It In 2025?
What Is Next Js And Why Should You Use It In 2025?

