Static Site Generation in React
By Syncfusion®, Inc. · Last updated
How SSG works: build-time rendering, static HTML generation, the build process, build-time data fetching, dynamic routes, deployment to a CDN, SSG pros and cons, and a Documentation Website capstone to download.
Introduction to Static Site Generation
Static site generation (SSG) means React renders your pages once, at build time, into plain HTML files. You upload these files to a host. Every visitor then gets a ready-made file. Nothing is rendered when they visit.
It is a third render mode, next to CSR and SSR:
When is the HTML made? CSR in the browser, SSR on each request, SSG once at build time CSR
made in each browser, after the JavaScript loads SSR
made on the server, for every request SSG
made once, at build time, before anyone visits
All three use the same React components. Only the time and place change.
Real-World Example
A bookshop's help center has 30 pages, such as "Shipping" and "Returns". The text changes only a few times a year.
At build time, the build script renders every page to an HTML file. The host sends these ready files to every visitor, so the pages load very fast and no server code runs.
Benefits of SSG
- Very fast. The files are ready. A host or CDN just sends them.
- Cheap and simple hosting. Any static host works. No Node.js server is needed.
- Great SEO. Every page is full HTML, like SSR.
- Safe and reliable. No server code runs per request, so there is less that can break or be attacked.
SSG is a great fit for content that does not change every minute: documentation, blogs, marketing pages and portfolios.
SSG Architecture
Build-Time Rendering
Build time is when you run npm run build, on your computer or a build server. Request time is when a user visits the site.
In SSG, React renders at build time. In SSR, it renders at request time. That is the main difference.
Static site generation: pages are rendered once at build time, then the same files are sent to every visitor
npm run build once
React renders pages
index.html
docs/*.html
CDN stores files Later: every visitor gets a ready file. Nothing is rendered per request.
The work happens before anyone visits.
Static HTML Generation
During the build, a script calls React for each page, and saves the result as a file. For pure static pages, React has renderToStaticMarkup. It is like renderToString, but it leaves out extra markers that only hydration needs, so the HTML is a little smaller.
import { renderToStaticMarkup } from "react-dom/server";
const html = renderToStaticMarkup(<DocPage doc={doc} />);
fs.writeFileSync("dist/docs/props/index.html", html);
If the page also needs to be interactive later, use renderToString and hydrate it in the browser, like in SSR.
Pre-Rendered Pages
The output is a folder of pre-rendered pages: .html files that already contain the content. Each URL maps to a file:
/→index.html/docs/props/→docs/props/index.html
Run the lab. The "build" renders three pages. Click a file to see its HTML.
SSG Rendering Fundamentals
Build Process
A typical SSG build has four steps:
- Read the content (files, a CMS, an API).
- List every page that must exist. This list of paths is often made by a function called
getStaticPaths. - Render each page with React.
- Write each result as an
.htmlfile in thedistfolder, together with CSS, JavaScript and images.
The build process: read content, list the pages, render each one, write the files
1. Read content + data
2. List paths getStaticPaths
3. Render each page
4. Write dist/*.html
runs on your computer or a CI server, not when users visit
After the build, the site is just a folder of files.
Page Generation
Each path becomes one file. The same layout component is used for every page, so all pages look alike. Pages are made one after another, so a site with 1,000 pages makes 1,000 files. A big site can take a while to build.
Serving Static Content
After the build, there is no React work left for visitors. The host just finds the file for the URL and sends it.
The simulator below compares SSR and SSG. Press Send 5 requests and compare how many times each one renders.
Easy Way to Remember: CSR renders in the browser, SSR renders per request, SSG renders once per build.
Content Generation
Build-Time Data Fetching
Pages often need data: posts from an API, docs from files. In SSG, this data is fetched during the build, once. The result is baked into the HTML. Visitors never wait for it.
Generating Dynamic Routes
A dynamic route like /blog/[id] is one template for many pages. At build time, you must say which ids exist. You fetch the list, and make one path per item. Then each path is rendered with its own data.
The lab does both. The "build" fetches the posts, makes one path per post, and renders a file for each.
Generating dynamic routes: one template plus a list of slugs makes many HTML files
/docs/[slug] one template
slugs from data
docs/introduction/index.html
docs/installation/index.html
docs/props/index.html
Add a doc to the data, rebuild, and a new page appears.
Managing Static Content
Content for SSG sites usually lives in one of these places:
- Files in the project, like Markdown (
.md) files. Writers edit text, not code. This is common for docs and blogs. - A headless CMS, an online editor (such as Contentful or Strapi) that the build reads through an API.
- Data files like JSON, for lists such as products or team members.
Keep content separate from components. Then the layout can change without touching the text, and the text can change without touching code.
Tools like Astro, Next.js (static export), Gatsby and VitePress do SSG for you. They give you getStaticPaths-style functions, Markdown support and a build command. The ideas in this lesson are the same in all of them.
Deployment and Delivery
Static Assets
Static assets are files that do not change per visitor: the HTML pages, CSS, JavaScript bundles, images and fonts. After an SSG build, the whole site is static assets. Build tools add a short code (a hash) to file names like index-4zsi.js. When the file changes, its name changes, so browsers never use an old copy.
Content Delivery Workflow
You upload the dist folder to a static host such as Netlify, Vercel, Cloudflare Pages or GitHub Pages. Most of them use a CDN (Content Delivery Network): copies of your files are kept on servers around the world. Each visitor gets the files from the nearest one.
Content delivery: a CDN keeps copies of the files near users all over the world
Origin dist/ folder
CDN Mumbai copy
CDN London copy
CDN New York copy
Each user gets the files from the nearest copy, so pages load fast.
Updating Generated Pages
Static pages do not change by themselves. To update one, you change the content, rebuild and deploy again. Most hosts do this automatically when you push to Git.
Try it below. Edit the price, and see that the live site still shows the old one until you rebuild and deploy.
Updating generated pages: change the content, rebuild, deploy
Edit content fix a typo
Rebuild npm run build
Deploy upload dist/
until you deploy, visitors still see the old files
Static pages change only when you build again.
Advantages and Limitations of SSG
| Advantages | Limitations |
|---|---|
| Fastest delivery: files are ready | Content is only as fresh as the last build |
| Cheap hosting on any static host or CDN | Big sites can take a long time to build |
| Full HTML for SEO and link previews | Not for per-user pages (a cart, a dashboard) |
| No server code per request: safe and reliable | Every change needs a rebuild and deploy |
| CSR | SSR | SSG | |
|---|---|---|---|
| When HTML is made | In the browser | On each request | Once, at build time |
| First view | Slow | Fast | Fastest |
| Fresh data | Yes | Yes | Only after a rebuild |
| Hosting | Static files | Node.js server | Static files |
| Best for | Apps behind login | Dynamic public pages | Docs, blogs, marketing |
Many real sites mix modes: SSG for docs and marketing pages, SSR for search results, and CSR for the logged-in dashboard. Interactive parts of an SSG page can still be hydrated, like in SSR.
Capstone Project: Documentation Website
You will build a Documentation Website for "Book Corner UI", a pretend component library. It has docs grouped into categories, a shared layout with a sidebar, and one static page per doc, made at build time.
Create multiple documentation pages
All content lives in data.ts: each doc has a slug (its URL name), a title, a category and its body. DocPage shows one doc. To add a page, you add an item to the data. No new component is needed.
Create reusable layout components
DocsLayout wraps every page with the same header and sidebar. It takes current (the active slug) and children (the page content). Each page looks consistent, and the layout is written once.
Organize content using categories
groupByCategory(docs) turns the flat list into groups: Getting Started, Core Concepts and Guides. The sidebar shows one heading per category with its docs below. Click the sidebar links in the lab to switch docs.
Configure dynamic documentation routes
The route /docs/[slug]/ is one pattern for all docs. getStaticPaths() in build.tsx lists every real path: / plus one /docs/<slug>/ per doc.
Generate pages at build time
build() loops over the paths, renders each page with renderToStaticMarkup inside DocsLayout, and stores it as a file like docs/props/index.html.
Implement navigation and routing
The sidebar uses plain <a href="/docs/props/"> links. On a static site, each click asks the host for the next HTML file. The host finds docs/props/index.html and sends it. No React runs for the visit.
The finished lab plays both parts: it runs the build once, then acts as the static host. Click the sidebar links. The console shows that each page is a file lookup, not a render.
Download Project Files
Download SSG Project Source Code
The complete Documentation Website is ready as a real SSG project with Vite, React, TypeScript and React Router. The docs are Markdown files. npm run build pre-renders one HTML file per doc into dist/static. In the browser, the pages are hydrated, so moving between docs is instant.
Download SSG Project: Download Documentation Website Project
docs-website/
package.json scripts and dependencies
prerender.js build step: render every route to dist/static
vite.config.ts Vite settings
index.html template with <!--app-html-->
content/docs/ the Markdown docs, one folder per category
src/
entry-client.tsx hydrate (or render in dev)
entry-server.tsx render(url) + getStaticPaths()
App.tsx routes
content/docs.ts reads and parses the Markdown at build time
layouts/DocsLayout.tsx
components/ Sidebar, Header, DocNav (previous / next)
pages/ HomePage, DocPage, NotFoundPage
Project Setup Instructions
- Install Node.js 18 or newer from nodejs.org, if you do not have it.
- Download the ZIP with the link above, and unzip it. You get a folder called
docs-website. - Open a terminal in that folder (in VS Code: File, Open Folder, then Terminal, New Terminal).
- Install the packages and start the dev server:
npm install
npm run dev
Open http://localhost:5173. To make the static site, run npm run build, then npm run preview to serve the generated files from dist/static. Add a new .md file in content/docs, build again, and a new page appears.
After npm run build, open the dist/static folder. You will find a real index.html for every doc, already filled with its text. That folder is the whole website: you can upload it to any static host.
Common mistakes
| Mistake | What you see | Fix |
|---|---|---|
| Expecting content changes to show without a rebuild | The live site still shows old text | Rebuild and deploy, or let the host build on every push |
| Using SSG for per-user data, like a cart | Every visitor sees the same page | Load user data on the client, or use SSR |
Forgetting a slug in getStaticPaths | That page is a 404 | Make the paths from the same data as the pages |
Using window while rendering at build time | Build error: window is not defined | Use browser-only code in useEffect |
| Mixing content into components | Every text change needs a code change | Keep content in Markdown or data files |
Using renderToStaticMarkup for pages you want to hydrate | Hydration warnings, clicks do not work | Use renderToString for pages that will be hydrated |
Check Yourself
Exercises
What to Remember
- SSG renders pages once at build time into HTML files. Visitors get ready files from a static host or CDN.
- The build reads content, lists paths with
getStaticPaths, renders each page and writes the files. Dynamic routes become one file per item. - SSG is fast, cheap and great for SEO, but content is only as fresh as the last build. Use it for docs, blogs and marketing pages.
Next: Incremental Static Generation