Static Site Generation Explained: How Astro Pre-Builds HTML

Learn how static site generation works, how Astro builds HTML before visitors arrive, and when SSG offers a simpler performance model than WordPress.

Quick answer

What is static site generation?

Static site generation (SSG) pre-renders pages into HTML during a build. When someone visits, the host can serve the generated file instead of running application code and database queries for that request. Astro uses static generation by default, while selected routes can be rendered on demand.

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 uncached page request triggered WordPress, which triggered PHP, which queried the database and assembled the page, thousands of times per hour, for pages whose layout and core content had not changed in days.

When I finally moved the repeatable content pages to a static architecture, the server load dropped noticeably. The product data still changed on a schedule, but those updates triggered controlled rebuilds. Visitors received pre-built HTML instead of forcing WordPress to assemble the same page structure again and again.

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


What happens during an uncached WordPress request

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

The exact sequence depends on the hosting stack, theme, plugins, and cache layers. When a request is not fulfilled by a full-page or edge cache, a WordPress page commonly follows a flow like this:

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

The important distinction is that steps 2-9 require application work when the request misses every full-page cache layer. A cache hit may bypass most or all of this sequence.

How long an uncached request takes varies widely. Hosting quality, theme and plugin code, database health, external calls, and current traffic all matter. A well-tuned WordPress site can respond quickly; a poorly optimized site or an overloaded origin can take much longer.

Full-page caching stores the generated response so WordPress does not have to repeat the same work for every visitor. It is effective, but it adds another system to configure and understand: cache warming, invalidation, storage, hit rates, and the behavior of pages that cannot be cached.

Static generation changes the default model by creating the page before the request arrives.


What happens when someone visits a static Astro page

1. Visitor's browser sends request to CDN
2. CDN serves the generated HTML from an edge cache or fetches it from the deployment origin
3. CDN sends the HTML to the browser
4. Browser renders the page

For a pre-rendered route, no WordPress application, PHP process, or database query is needed to assemble that page during the request. The HTML already exists.

CDN caching still exists, but a static hosting platform usually manages it as part of the deployment and delivery layer rather than relying on a WordPress page-cache plugin.

WordPress request flow compared with Astro static HTML delivery
An uncached WordPress request commonly assembles a page through PHP and the database, while Astro can serve HTML generated before the visit.

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?

For an uncached dynamic WordPress request, the page-generation work happens at request time, when someone visits.

For an Astro route configured for prerendering, the page-generation work happens at build time, before anyone visits.

Run npm run build in your Astro project:

npm run build

Astro reads your content and templates and generates the production output. Routes configured for prerendering become HTML files inside the dist/ folder:

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

For a fully static project, each page route is represented by generated output that can be deployed to a static hosting service such as Vercel, Netlify, Cloudflare Pages, or an object-storage setup configured for website hosting.

Those pre-rendered pages do not need PHP, a database, or a long-running Node.js application at request time. Routes that you later choose to render on demand are a different case and require a compatible server adapter.

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 effective full-page caching can serve anonymous pages very quickly. The difference is not that WordPress cannot be fast. The difference is where the complexity lives.

WordPress with full-page caching:

  • A cache miss can trigger PHP, WordPress, and database work
  • Content changes may require cache invalidation or regeneration
  • Caching may be implemented through a plugin, the web server, a CDN, or several layers together
  • Dynamic and personalized pages may bypass the full-page cache
  • The cache stack becomes part of the system you monitor and maintain

Static delivery:

  • The HTML already exists before the request arrives
  • A pre-rendered page does not require PHP or a database query to be assembled
  • No WordPress full-page cache plugin is required
  • CDN caching is usually handled by the deployment platform
  • A new deployment publishes a new or versioned set of generated files

Static generation therefore gives content pages a strong server-response baseline without requiring an application-level page cache. It does not guarantee a fast page by itself: oversized images, fonts, JavaScript, third-party scripts, and poor frontend design can still make a static site slow.

WordPress caching stack compared with static file delivery
WordPress can become fast through a caching stack, while static generation removes most application work from requests for pre-rendered pages.

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, most of that traffic can be served from cached copies at CDN edge locations. Even when an edge location needs to fetch the generated file from the deployment origin, it does not need to run WordPress, PHP, and a database query to assemble the page. The origin therefore performs far less work, so a sudden spike is usually easier to absorb.

Dynamic WordPress server and static CDN handling a traffic spike
Without a full-page cache hit, dynamic rendering concentrates work at the origin. A generated static file can be distributed across CDN edge locations without repeating that application work.

A WordPress site with correctly configured full-page edge caching can behave similarly for anonymous visitors. The difference is that static generation starts with an already-generated page, while WordPress needs the cache and origin behavior to be configured correctly.

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 pure static HTML cannot do by itself

Let’s be honest about the limits.

Keep real-time data current inside the pre-rendered HTML. A generated file cannot update its own stock prices, inventory, or account data after deployment. You need to rebuild the page, fetch current data in the browser, or render that route on demand.

Accept user-generated content without a dynamic service. Comments, forum posts, account profiles, and form submissions need somewhere to validate and store data. A static frontend can connect to services such as Supabase or a dedicated comments platform, but those dynamic systems still exist behind the page.

Run database-backed search by itself. WordPress can query its database at request time. A static site usually builds a search index for a client-side tool such as Pagefind or sends searches to an external service such as Algolia.

Give non-technical editors a dashboard automatically. A client cannot be expected to edit Markdown and run a build. They need a CMS layer such as TinaCMS, a headless CMS, or a dynamic CMS such as WordPress.

Static generation can still be one part of an architecture that includes all these features. The key is recognizing which parts can be pre-rendered and which parts genuinely need live application behavior.


Mixing static and on-demand routes

Astro is not all-or-nothing. In its default static output mode, Astro pre-renders routes during the build. After adding an adapter for a supported server platform, you can opt an individual page or endpoint out of prerendering:

---
export const prerender = false
---

The rest of the site can remain static. A content project might use:

  • A pre-rendered blog → generated HTML files
  • A pre-rendered review section → generated HTML files
  • A contact endpoint → handled on demand
  • A protected account or admin area → rendered on demand

People often describe this as a hybrid architecture because static and dynamic behavior exist in the same project. In current Astro configuration, however, you do not select a separate hybrid output mode. You keep the static default and opt selected routes into on-demand rendering with a server adapter.

Static, dynamic, and mixed website rendering use cases
A single Astro project can pre-render content pages while selected routes handle personalized or frequently changing data on demand.

This series returns to on-demand rendering in the backend section, after the static foundation is clear.


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 the generated folder for each edit. You push the change, the platform runs the configured build, and a new deployment becomes live. Build and deployment times vary with the number of pages, integrations, and hosting platform.

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 to see what Astro generated.

To test the production output correctly, run:

npm run preview

Open the local URL printed by Astro. This serves the generated output over HTTP, which matters because direct file:// URLs can break absolute asset paths, JavaScript modules, and nested routes.

That is the core of static site generation: source files and templates go into a build, and deployable output comes out.


Next step: deploy the generated site

Now that you know what Astro puts inside dist/, the next step is to publish that output through a Git-based deployment workflow. Continue with How to Deploy Astro to Vercel: From Local to Live in 5 Minutes.

Frequently Asked Questions

What is the difference between static and dynamic websites?
A dynamic website can generate a page when a request arrives by running application code and querying a database. WordPress commonly works this way when a request is not fulfilled by full-page or edge caching. A statically generated page is created during a build and can be served as an existing HTML file. Astro pre-renders routes by default.
Is static site generation right for every website?
No. SSG works especially well for blogs, documentation, review sites, portfolios, and other content that does not need to be regenerated for every visitor. Pure pre-rendered HTML cannot keep live prices, inventory, or personalized account data current by itself, but a static page can fetch data in the browser or an Astro project can render selected routes on demand.
How fast is a static site compared to WordPress?
There is no universal response-time difference because performance depends on hosting, caching, page weight, scripts, images, and traffic. Static generation removes PHP and database work from requests for pre-rendered pages. A WordPress site with effective full-page edge caching can also be very fast, but it has more runtime infrastructure to configure and maintain.
What does npm run build do in Astro?
It runs the Astro build process, reads your content and templates, and writes the deployable output to the dist/ folder. Routes configured for prerendering become HTML files. After building, use npm run preview to test the production output through a local server rather than relying on file:// URLs.
What happens when you add a new blog post to a static site?
You add the content file and trigger a new build. With a Git-based deployment service such as Vercel or Netlify, pushing the change can automatically start the build and publish a new deployment. The exact build and deployment time depends on the project and hosting platform.