Static Site Generation Explained: Why Pre-Built HTML Beats WordPress's On-Demand Approach

What SSG actually is, how it differs from WordPress's dynamic rendering, and why a folder of HTML files can outperform a fully optimized WordPress setup, explained with real examples.

Quick answer

What is static site generation?

Static site generation (SSG) is a build process that pre-generates all pages as plain HTML files before anyone visits. Instead of building pages on each request like WordPress, SSG builds everything once and serves the pre-built files, making pages load faster with no server processing required.

Static site generation diagram comparing WordPress request-time rendering with Astro build-time HTML output
First-hand experience: Based on direct hands-on use. I ran a WordPress price comparison site on increasingly beefier servers before moving to a static architecture. The performance difference was not subtle.

I spent months trying to make a WordPress site fast enough.

Not a blog. A price comparison site with tens of thousands of products, constant price updates, and traffic that would spike unpredictably when a deal went viral on Facebook.

I tried everything: FastCGI cache, Redis object caching, WP Rocket, a CDN, image optimization, database query optimization, upgrading the VPS more than once. Each step helped. None of it was enough.

The site was architecturally the wrong tool for the job. Every page request triggered WordPress, which triggered PHP, which triggered the database, which assembled the page and sent it, thousands of times per hour, for pages that hadn’t changed in days.

When I finally moved the static pages to a static architecture, the server load dropped noticeably. The same content, served as pre-built HTML instead of assembled-on-demand PHP, just… worked.

That experience taught me more about static site generation than any tutorial could.


What actually happens when someone visits a WordPress page

To understand static site generation, you first need to understand what the alternative looks like under the hood.

When someone visits a WordPress blog post:

1. Visitor's browser sends request to your server
2. Server receives request, wakes up PHP
3. PHP loads WordPress core files
4. WordPress parses the URL, identifies the post
5. PHP connects to MySQL database
6. Database query runs to fetch post content, title, meta, comments
7. WordPress applies theme template to the data
8. PHP outputs completed HTML
9. Server sends HTML to browser
10. Browser renders the page

That’s 10 steps. Steps 2-9 happen on your server, every single time, for every single visitor.

With a fast server and good caching, this can happen in 200-300ms. On a slow server or under heavy traffic, it can take 2-5 seconds.

And caching, which is what WordPress sites rely on to be performant, just stores the output of steps 2-9 so it doesn’t have to repeat them every time. The cache itself adds a layer of complexity: cache warming, cache invalidation, cache storage space, cache hit vs miss rates.

You’re solving a problem that static generation avoids entirely.


What happens when someone visits a static Astro page

1. Visitor's browser sends request to CDN
2. CDN finds the pre-built HTML file
3. CDN sends HTML to browser
4. Browser renders the page

Four steps. Steps 2-3 happen on a CDN edge server close to the visitor. No PHP. No database. No cache management.

The HTML file already exists. The server just delivers it.

WordPress request flow compared with Astro static HTML delivery
WordPress commonly assembles a page through PHP and the database when someone visits, while Astro can serve HTML that already exists.

This is why static sites can feel fast before you add much optimization. A WordPress site can also be fast, but it usually needs a tuned stack, caching, and more ongoing attention.


The build step: when does the work happen?

In WordPress: the work happens at request time, when someone visits.

In Astro: the work happens at build time, before anyone visits.

Run npm run build in your Astro project:

npm run build

Astro reads all your content files, applies your templates, and generates complete HTML files for every page. The output goes to a dist/ folder:

dist/
├── index.html
├── blog/
│   ├── hello-world/
│   │   └── index.html
│   └── astro-vs-wordpress/
│       └── index.html
├── reviews/
│   └── hostinger-review/
│       └── index.html
└── assets/
    └── styles.css

Every page is a real HTML file. Deploy this folder to any static hosting service (Vercel, Netlify, Cloudflare Pages, even a plain S3 bucket) and your site works.

No PHP required. No database required. No Node.js required at runtime. Just files.

VS Code showing Astro npm run build output and generated files in the dist folder
Running npm run build turns Astro source files into deployable HTML, CSS, JavaScript, and assets inside the dist folder.

Why this matters for performance

WordPress with excellent caching can serve cached pages fast. But “fast with caching” and “fast by default” are different things:

WordPress with caching:

  • Cache miss → full PHP + database execution
  • Cache needs warming after deploys
  • Cache needs to be invalidated when content changes
  • Cache storage takes server resources
  • Cache plugin adds another dependency to maintain

Static serving:

  • Every request hits a pre-built file
  • No cache to warm
  • No cache to invalidate (deploy creates new files)
  • No storage overhead beyond the files themselves
  • No plugin dependency

The WordPress approach can achieve similar performance to static, but only with correct configuration and at the cost of ongoing maintenance. Static achieves it by default with nothing to configure.

WordPress caching stack compared with static file delivery
WordPress can become fast through a caching stack, but static delivery removes most of that runtime work entirely.

The real cost of dynamic rendering at scale

When I was running that price comparison site, a single viral Facebook post could send a sudden spike of visitors to the same product page within the hour.

On WordPress, that could mean fresh PHP execution and database queries during the worst possible moment, especially after cache purges, fresh deploys, or pages that had not been warmed yet.

The server struggled. Response times climbed, and some requests timed out.

On a static architecture, that same spike just means a wave of CDN cache hits. The CDN doesn’t struggle. Response times stay fast and consistent. The server, if there’s even a server, doesn’t notice.

Dynamic WordPress server and static CDN handling a traffic spike
A dynamic WordPress site concentrates work at the origin server, while a static site can distribute the same pre-built file across CDN edge nodes.

This is why static generation is not just a developer preference. For repeatable content pages under traffic spikes, it can be the simpler architecture.


What static generation can’t do

Let’s be honest about the limits.

Real-time data. If your page shows live stock prices, live inventory, or user-specific content, static generation can’t help you. The HTML is built once. It doesn’t update until you rebuild.

User-generated content. Comments, forum posts, and user profiles all require a database and server-side logic. Static sites handle this with external services (Disqus for comments, Supabase for data), which adds complexity.

Complex search. A WordPress search queries the database in real time. Static search requires a client-side search library or an external search service like Algolia or Pagefind.

Client-editable content without a CMS layer. A non-technical client can’t edit a Markdown file and trigger a build. They need a CMS interface: either something like TinaCMS on top of the static site, or a fully dynamic CMS like WordPress.


Hybrid rendering: the best of both worlds

Astro isn’t all-or-nothing. You can have mostly static pages with a few server-rendered routes.

A content site that’s 95% static can have:

  • A static blog → plain HTML files
  • A static review section → plain HTML files
  • A contact form → one server-side API route
  • An admin section → server-rendered, protected routes

This is called hybrid rendering. Astro supports it natively. Build static where you can. Add server rendering where you need it.

Static, dynamic, and hybrid website rendering use cases
Static rendering fits content pages, dynamic rendering fits personalized app data, and hybrid rendering lets one project use both.

This series covers that in the backend section, after you understand the static foundation first.


How the build fits into the workflow

Once you understand SSG, the Astro workflow makes sense:

Write content → Run build → Deploy dist/ folder → Site is live

With Vercel or Netlify connected to GitHub, the last two steps are automatic:

Write content → git push → Vercel builds → Site is live

With that Git-based workflow, you do not manually upload files or SSH into a server to clear a page cache. You push code, the build runs, the site updates.

Astro publishing workflow from MDX content to a live website
In an Astro publishing workflow, content changes move through Git, build, deploy, and then appear as a new live version of the site.

For a solo developer or a small technical team managing a content site, this workflow is cleaner than the WordPress deployment flow I used for years.


Running your first build

Try it now on the demo project. In your terminal:

npm run build

Watch the output. Astro will list every page it generates:

 dist/index.html
 dist/blog/hello-world/index.html
 dist/blog/astro-vs-wordpress/index.html
 dist/reviews/hostinger-review/index.html
 dist/guides/how-to-deploy-astro/index.html
...
 Built in 2.34s

Then look inside the dist/ folder. Open one of those HTML files in a browser directly, not via localhost, just double-click the file. It renders.

That’s static site generation. A folder of files that work anywhere.


Frequently Asked Questions

What is the difference between static and dynamic websites?
A dynamic website builds pages at request time. A visitor arrives, the server runs code, queries a database, and assembles HTML to send back. WordPress is dynamic. A static website serves pre-built HTML files directly, with no server processing and no database query on each visit. Astro uses static generation by default.
Is static site generation right for every website?
No. SSG works best for content that doesn't change in real time, like blogs, documentation, review sites, portfolios, and marketing pages. It's not suitable for sites that need real-time data, user-specific content, or live inventory. Astro supports hybrid rendering for projects that need both static and dynamic pages.
How fast is a static site compared to WordPress?
A static site served from a CDN can often respond in a few hundred milliseconds because the HTML already exists. An unoptimized WordPress site can take several seconds, and a well-optimized WordPress site needs caching, tuning, and maintenance to stay fast. Static serving removes much of that runtime work.
What does npm run build do in Astro?
It runs the Astro build process. It reads all content files and templates, generates complete HTML pages for every route in your project, and outputs everything to a dist/ folder. That folder is what you deploy. The build typically takes 5-30 seconds for a content site, and runs automatically when you push to GitHub with Vercel connected.
What happens when you add a new blog post?
You create the content file, commit to Git, and push. Vercel or Netlify detects the push, runs npm run build automatically, and deploys the updated site. For small content sites, the new page is usually live within a minute or two. No manual file upload. No page cache to clear.