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.
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.
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.
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.
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.
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.
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.