Escaping the Ghost: Moving to Astro and Cloudflare Pages
How I migrated from a dynamic Ghost CMS to a blazing fast, statically generated Astro site on Cloudflare Pages.

For years, Ghost has been the default recommendation for anyone who wants a serious publishing platform without the bloat of WordPress. It is sleek, focused, and has a fantastic editor.
But as your site grows, you start noticing the friction.
Running a dynamic Node.js application means managing servers. It means dealing with reverse proxies, keeping databases updated, and constantly fighting performance bottlenecks.
A blog is fundamentally a read-heavy workload. Why generate the same HTML thousands of times per day?
The 76/100 Lighthouse Trap
Ghost is fast, but it is not edge-native fast.
Every time a user visits the site, the request hits a server, queries a database, renders a template, and serves the response. You can put CDNs and caching layers in front, but the core architecture remains dynamic.
This results in a frustrating ceiling when optimizing for performance. Despite tweaking Cloudflare rules and aggressively compressing images, the Google Lighthouse performance score was stubbornly stuck at 76.
The Time to First Byte (TTFB) was too high. The Largest Contentful Paint (LCP) was delayed by server rendering time.
It was time to rethink the stack entirely.
Moving to Astro: Static, but not static
Astro is designed for content-driven websites. It flips the dynamic model on its head.
Instead of rendering pages on demand, Astro renders them at build time. There is no database. There is no backend server to maintain. The entire blog is just a collection of Markdown files in a Git repository.
When you push a commit, Astro takes those Markdown files, applies your components (in my case, a custom Astro adaptation of the classic Ghost Casper theme), and spits out pure, static HTML.
No JavaScript is sent to the browser unless explicitly needed. This is what Astro calls “Zero-JS by default” Island Architecture.
Deploying to the Edge with Cloudflare Pages
Removing the backend solves half the problem. The other half is delivery.
Instead of hosting the static files on a traditional VPS, the site is now deployed on Cloudflare Pages.
This changes everything about how the site is served:
- Global Edge Network: The static HTML is distributed across Cloudflare’s edge locations worldwide. Visitors in New York or Tokyo get the site served from a data center a few miles away.
- Zero Maintenance: No servers to patch. No Node.js version updates. No MySQL backups.
- Built-in CI/CD: Every time a commit is pushed to the
mainbranch on GitHub, Cloudflare automatically spins up a build environment, runsastro build, and deploys the new version in under 40 seconds.
The Agentic Workflow
The best part of this migration? The workflow is now entirely automated, driven by Agentic AI.
Writing an article looks like this:
- I write the content in Markdown.
- An autonomous agent reads the draft, generates a custom Hero image, converts it to WebP, and scales it perfectly for high-DPI screens.
- The agent commits the changes to an isolated Git branch and opens a Pull Request.
- Cloudflare Pages instantly generates a secure, private Preview URL (
.pages.dev). - I review the preview, click “Merge”, and the site goes live globally.
The 100/100 Result
The shift from dynamic rendering to static edge delivery produced immediate results.
The Lighthouse performance score went from 76 to a perfect 100/100. Time to Interactive is near zero. The Largest Contentful Paint (LCP) dropped to under 1 second.
I even optimized the CSS for strict WCAG AA Accessibility, ensuring perfect contrast ratios for both light and dark modes.
Sometimes, the best way to scale an application is to remove the application entirely.
But honestly, the real highlight of this migration was how it got built. I ran this entire project using agy (Antigravity CLI). Going in, I fully expected to be working with the idiot brother of Opus, a glorified autocomplete that I’d have to spoon-feed every single CSS selector. Instead, I found myself wrestling with an AI that had a surprisingly proactive, and frankly, somewhat impertinent soul. It would confidently write entire Astro components in milliseconds, argue with me about mobile layout breakpoints, and occasionally push a 300-pixel black abyss to the production footer just to remind me who’s actually writing the code.
Despite the attitude, it did an exceptional job. I just had to provide the biological intuition, complain when “the bottom of the site is messed up”, and occasionally press the “Merge” button.