We moved a client from dedicated WordPress hosting with a CDN to an Astro-built site on a European VPS. Load times dropped from 1.2 seconds to 400–800 milliseconds. Monthly hosting costs fell by 75%. The CDN is gone. WordPress is untouched. Here's exactly what we did, why removing the CDN helped, and what this migration actually involved.
What We Inherited
The client had a content-heavy WordPress site built up over years: a substantial blog with custom layout blocks, ACF relationship fields connecting posts to other content types, nested repeater fields, flexible content blocks for different layout arrangements, and global options pages controlling site-wide settings. Complex, well-structured, and entirely worth keeping. The kind of WordPress setup nobody wants to burn down.
The infrastructure behind it was purpose-built for WordPress: dedicated hosting with a CDN in front to offset the load and improve delivery times. On paper, solid. In practice, 1.2 seconds time-to-first-byte on a good day, and a hosting bill that made up a significant share of the annual budget.
The brief was not "rebuild the site." It was: make this faster, reduce the cost, and don't disrupt the content workflow.
Keep WordPress. Remove It from the Frontend.
Not a rebuild. A decoupling.
Astro fetches all content from WordPress at build time — posts, ACF field data, relationship references, repeater content, layout block configurations, options page values. It resolves those into static HTML and deploys to the VPS. When a visitor loads a page, they're receiving pre-rendered HTML. No PHP executing. No database queries running. No WordPress process handling the request.
WordPress continues exactly as before. The client logs in, writes posts, edits fields, manages content relationships — the workflow they've built over years is unchanged. They didn't need retraining. They didn't need to learn a new editorial interface. The content investment was preserved completely.
This is the part that surprises most people who hear the word "headless": you don't have to choose between modern frontend performance and keeping WordPress as your CMS. The migration isn't away from WordPress. It's the frontend layer that changes.
What the ACF Migration Actually Involved
"Complex ACF setup" is easy to say. What it meant in practice:
The site used the full ACF feature set. Relationship fields linked posts to products, case studies, and team members — and the WordPress REST API returns these as IDs that need to be resolved into full objects on the Astro side. Nested repeaters (repeater fields containing other repeaters) come back as arrays of arrays, which require careful type-handling to avoid runtime errors during the build. Options page data — global settings that apply across the entire site — lives at a separate REST endpoint and needs its own fetch call outside the standard posts query.
The blog layout blocks were the most involved piece. The blog used flexible content blocks in WordPress: different column arrangements, image-and-text combinations, pull quotes, call-out blocks — each with its own template in the WordPress theme. Every one of those had to become an Astro component. Since Astro has no browser-side rendering, the block-type switching logic (render this component for layout type A, this one for type B) runs at build time, not at runtime.
The result: every layout block the client built in WordPress now renders in Astro, fully styled, pixel-accurate. The editorial experience in WordPress didn't change at all. The delivery is entirely different.
Why Removing the CDN Made It Faster
This is the part that runs counter to most infrastructure instincts.
CDNs improve performance by moving content closer to the user. That logic holds when the origin server is far from the audience — a US-hosted server serving European visitors, for example. The CDN caches content at PoPs in Frankfurt, Amsterdam, or Paris, reducing round-trip time to the origin.
But when the origin server is already in Europe and the audience is European, the CDN adds a hop instead of removing one. The request hits the CDN edge node. If the response isn't cached — which happens more often than CDN providers will tell you, especially for pages with query parameters, logged-in state checks, or low traffic — it falls through to origin anyway. For a mostly-static site with no real-time personalization, the CDN's contribution to cache hit rate rarely justifies the architecture it adds.
On the new setup: European VPS, European audience, no intermediary. The request goes directly to the server and gets back pre-rendered static HTML. 400–800ms.
There's a second benefit that matters specifically for clients in the EU. No CDN means no third-party infrastructure routing visitor requests. Cloudflare and Fastly have data centers in Europe, but they are US companies operating under US jurisdiction — CLOUD Act, FISA, and related provisions apply regardless of where the PoP is located. For clients where GDPR compliance is a real concern and not just a checkbox, removing that intermediary is a meaningful architectural decision, not a footnote.
The Numbers
Before:
- Time to interactive: ~1.2s
- Hosting: dedicated WordPress server + CDN subscription
- Server resources: dedicated to running PHP and MySQL under every request
After:
- Time to interactive: 400–800ms
- Hosting cost: 75% lower (four times cheaper)
- Server resources: 150% more CPU and RAM than the previous setup — at a quarter of the price
- CDN: none
The resource increase explains the speed improvement better than any optimization tweak would. The old server was sized to handle WordPress PHP processes under concurrent load. The new VPS serves pre-rendered static files. The compute demand dropped to near zero, which is why a cheaper server with more raw capacity can outperform an expensive setup engineered specifically for WordPress.
400% cost reduction. 150% more resources. Load times cut by two-thirds. No CDN.
What the Migration Actually Unlocked
The performance numbers were what we were asked to deliver. What followed was more significant.
With Astro as the rendering layer, building new features stopped being a negotiation with WordPress's template system. No more layout builder constraints. No more re-wiring ACF fields through PHP template logic to get an output that matches the design. No more blocks that look correct in the editor and wrong in the browser.
The WordPress content architecture became a clean data API. Astro consumed it and rendered it without constraint. For the first time, the gap between what we wanted to build and what the system allowed us to build closed.
New sections, landing pages, interactive components, and performance-sensitive features — things that would have previously required custom plugins, builder workarounds, or painful PHP customisation — now get built in Astro directly. Properly. The way they should have been built. The site can grow on the Astro side without touching the WordPress content layer.
WordPress does what it's genuinely good at: structured content management with a mature, stable editorial interface that the client's team already knows. Astro does what WordPress's templating system was never designed for: maintainable, performant front-end output without a runtime overhead.
The builder pain is gone. The ACF wiring overhead is gone. The distance between intention and result collapsed.
When This Approach Makes Sense
It works well when:
- The WordPress content structure is worth keeping. A mature ACF setup with established relationships and editorial workflows is an asset, not a liability. If the content architecture is solid, there's no reason to rebuild it.
- Your audience is geographically concentrated and close to where you can host a VPS. The EU-hosting advantage doesn't apply if your users are globally distributed.
- The site is content-driven, not transactionally dynamic. If pages don't change based on user state at runtime, static rendering is a better fit.
- The client's team knows WordPress and shouldn't be asked to learn a new CMS. Editorial continuity has real value.
It's a poor fit when:
- E-commerce with real-time inventory or cart state. Static rendering can't handle per-user runtime data without additional architecture.
- Content updates need to be live within seconds. Astro requires a rebuild on publish — typically two to five minutes. For most editorial cadences, that's fine. For a breaking news operation, it isn't.
- The WordPress setup itself is the problem. Migrating the rendering layer won't fix a broken content architecture. If the ACF setup is tangled, the relationships are unclear, or the plugin stack is causing the slowdown, those need to be addressed first.
The rebuild trigger is the one genuine constraint of this architecture. On this project, publishing in WordPress kicks an automated rebuild. For the client's publishing frequency, the delay is invisible. Whether it fits your use case depends entirely on how time-sensitive your content updates are.
The Takeaway
This project started as a performance and cost brief. It ended as an architectural upgrade that changed what the team could build.
Four times cheaper. 150% more resources. Load times cut from 1.2 seconds to under half a second. No CDN. No GDPR-problematic intermediaries. WordPress still running exactly as the client expects it to.
And the work of building — the actual act of shipping features — became what it should have been all along.