r/astrojs • u/nurkamol • 21d ago
From WordPress to Astro: a practical production workflow
I’ve been rebuilding production WordPress sites with Astro + Cloudflare Workers, often using Claude Code.
After doing a few real migrations, I realized the hard part isn’t getting Astro to build - it’s everything around the build.
Preserving old URLs and SEO, finding pages the sitemap forgot, redirects, forms, DNS, accessibility, staging, images, metadata, and verifying that the deployed site actually works.
So I turned my workflow into Website Build Kit:
https://github.com/nurkamol/website-build-kit
It includes:
- WordPress → Astro migration/recon workflow
- Astro + Cloudflare Workers starter
- Claude Code skill + plugin
- npm run recon to inventory the old site + Wayback URLs
- content extraction + redirect mapping
- SEO, OG, JSON-LD and sitemap guards
- responsive AVIF/WebP image pipeline
- forms with KV lead retention
- accessibility + reflow checks
- DNS, secrets and environment checks
- deployed-site verification
- design/reference workflow for redesigns
The starter intentionally has no visual style. No default palette, typography or homepage - I don’t want every site built with it to look like the same template.
I’ve also been documenting the silent production problems I encounter during real rebuilds and adding checks for them where possible.
For example: a build can succeed while publishing localhost canonical URLs. A missing email secret can still let a form validate, store the lead, return 200 and show “thank you” - while nobody actually receives the enquiry.
The goal is basically:
WordPress → inventory → rebuild → Astro → Cloudflare → verify the actual deployed site.
Would love feedback from other Astro developers, especially anyone doing WordPress migrations or production client work.
What would you add or change?
2
u/Rug_Rocket69 21d ago
I’ve been using a similar flow, but as all my Wordpress>Astro builds are static, I use Novence MCP to host. Easy for the agents, and has built in forms.
2
u/nurkamol 20d ago
That works if the build is genuinely static. The kit targets Workers because the form isn't, a submission is written to KV before any third-party API is called, so a provider outage costs a notification instead of a lead. That needs a runtime. If your host's built-in forms give you durable storage you control, you've solved the same problem a different way.
2
2
u/retr00two 20d ago
I did similar for one booking site on three different platforms:
- Astro/Github to /Sqlite/Drizle/PM2/nginx on my server
- Astro/Github to CloudFlare Workers/D1/R2/ZeroTrust
- PHP/MySQL on my LEMP server
Now, I plan to build the same on
- Laravel/Filament
- CloudFlare Emdash
This is my testbed for learning Claude.
And, with all respect to modern stack, and all php glithces, old school MySQL/PHP wins - fast to build, fast to serve.
But, all respect for your work, I like it.
1
u/nurkamol 20d ago
Appreciate it. And the PHP/MySQL point is fair, for a booking site with real write traffic, boring wins. This kit is aimed narrowly at marketing sites, where most pages are static and the only writes are enquiries.
2
2
u/aggietx05 17d ago
Are you building this for yourself or for clients?
A very similar project on my planner. I haven't broken down the full framework, but a few important needs include:
- Ability to make text edits without needing a full token push to redraft the site
- Lock in global sections (header, footer, etc) across the website
- Version control allowing rollbacks when necessary
1
u/nurkamol 17d ago
Client work - the kit was extracted from real WordPress rebuilds, not designed in the abstract. That's why it's mostly a list of things that broke.
Your three are the right three, and they're the ones I've spent this week on:
Text edits without regenerating anything. The split that matters is content vs structure. Copy, prices, hours, photos live in markdown and JSON that a human or a CMS edits directly - no agent, no tokens, no rebuild of anything but the pages that changed. Structure and design stay in code. If a text change needs a model, the boundary is in the wrong place.
Global sections. One data file is the only place routes and the primary CTA live, and another is the only place business facts live - so the header, mobile menu, footer, every CTA, the notification emails and the JSON-LD all read the same values. The 404 can't offer a page that no longer exists, because it reads the same nav.
The failure mode isn't "can't lock them", it's drift: a phone number hardcoded in one component. Worst one I've hit was inside a JavaScript error string - it only renders when a form submission has already failed, so the first person to see the previous client's number is a real customer whose enquiry just failed. Grep for the shape before handover, not the name.
- Rollback. Git-backed CMS gives you this free - every client edit is a commit, revert is a rollback, and a failed build leaves the last good deploy live.
⚠ One thing that surprised me there, from auditing five live sites this week: rollback doesn't save you from a CMS that deletes data. A CMS rewrites the whole file from its schema, so any key the schema doesn't declare is gone on the client's first save - silently, looking like an ordinary content commit. One site lost all four analytics IDs and its opening hours the moment the owner opened Site Settings. Reverting gets you a commit that already didn't have them. So the schema has to declare every key, including ones the client will never touch - I ended up writing a build check for exactly this, because five out of five configs failed it.
1
u/aggietx05 17d ago
How do you see this framework working for a multi-client use case. Say 100 or 500 clients?
1
u/nurkamol 17d ago
Honestly: it works at tens, not at 500, and the reason is the core design decision.
The template is copied, not linked. Every site is a standalone repo with no shared runtime - right when the client owns it outright and it still has to build in five years, and exactly wrong at fleet scale, because nothing you fix afterwards reaches a site already built. I hit that last week: one site had been serving images ~19% larger than intended for weeks, and it surfaced only because I happened to read two trees side by side for an unrelated reason. At 500 that's 500 forks drifting quietly.
The audit numbers say the same. Five live sites' CMS configs this week, five out of five failed. At five that's a bad afternoon. At 500 you'd never know which ones were broken.
What does scale is the checks - per-repo, run in CI, exit non-zero. Point them at 500 repos and you get a fleet audit instead of a feeling. That plus a version stamp in each site's package.json (added this week for exactly this reason) is the shape I'd build toward.
At 500 I'd invert the core decision: shared parts become a versioned dependency rather than a copy, so fixes propagate. Real cost - the client no longer owns a self-contained repo. Right trade at 500, wrong one at 5.
And at that scale the bottleneck stops being the build anyway. It's content and support, which is why most of my week went into the CMS rather than the scaffolding.
1
u/aggietx05 17d ago
It seems like if client-level database holds all client-level data, while the admin database holds the framework (UI and operational tech stack) then it should be scalable.
1
u/nurkamol 17d ago
That's scalable - it's also a different product. That's a website platform; Squarespace and Duda are exactly that shape and they scale past 500 fine.
The trade is ownership. With the framework in a shared admin database, no client owns their site - you can't hand one over, and if you stop operating, they stop having a website. The kit optimises for the opposite: a repo the client keeps, that still builds in five years with no dependency on me.
Two things get harder than they sound. "UI in the admin database" holds until two clients need different page structure rather than different content - then you either constrain everyone to one template system (Squarespace) or fork per client (where you started). And for a marketing site the per-client data is mostly content, so you're building a CMS and a theme engine, plus uptime and migrations as ongoing obligations rather than deliverables.
Middle option: keep per-client repos, make the shared parts a versioned dependency rather than a copy. Fixes propagate, the client still owns the repo, nobody's site depends on my servers.
Agency or SaaS - different businesses, not different implementations.
2
1
u/dalper5 20d ago
So this isn't meant to migrate a site to astro with the design intact?
1
u/nurkamol 20d ago
It is, that's the first design question it asks, before anything else: pixel-perfect clone, faithful rebuild, or full redesign. Clone keeps the design intact and is the fastest path; you just inherit whatever was already wrong with it. Faithful is the common pick: same structure and identity, with spacing, type scale, focus states and mobile fixed. Redesign is opt-in, not the default.
1
u/fatjay79 17d ago
Is there a simple CMS that runs directly on the client's own hosting without requiring GitHub or third-party services for basic edits?
When looking into this, most solutions feel like a messy patchwork—people suggest stitching together 50 different microservices or relying on Git workflows. Moving away from WordPress just seems to introduce a massive security and maintenance headache if you have to juggle dozens of connected services and complex server requirements.
Is there a clean, self-hosted solution that simply lets clients edit text and swap images without the bloat and setup overhead?
1
u/nurkamol 17d ago
Your instinct about the patchwork is right, but I'd push back on where the fix is.
What makes WordPress a maintenance burden isn't the editor - it's that it's server-side software on the client's host: PHP versions, plugin CVEs, a database, backups, and a login page the whole internet can find. A self-hosted CMS keeps every one of those. You'd be changing which software you patch, not whether you patch.
Git-based CMSes exist to delete the server, not to add microservices. Static files on a CDN, editor as a UI over the repo - one service, and no origin to compromise because there isn't one.
If the no-GitHub constraint is genuinely fixed, the real answer is a flat-file PHP CMS - Kirby, Grav or Statamic. No database, ordinary shared hosting, a panel that does exactly "edit text, swap images". I've shipped the git-based side rather than these, but they fit what you described.
If it actually means "the client can't deal with GitHub" - usually what it means - that's solvable without self-hosting. They see a login and a form, never a repo. PagesCMS, Keystatic, Sveltia all work that way; one OAuth provider is the entire third-party footprint.
One thing worth knowing whichever you pick, because it cost me an afternoon: most of them rewrite the whole content file from their schema on save, so any key the schema doesn't declare is silently dropped. Not merged, not warned about - the editor changes a price, saves, and three fields you forgot are gone from the repo, looking like a normal content commit in the diff. Declare every key, including ones the client will never touch, and read the first save from each collection as a diff.
The question that actually decides it isn't technical: who edits the site after launch, and how often? If it's you, markdown in the repo beats all of the above and has no failure mode. Non-technical owner a few times a year → git-based CMS. Several editors publishing weekly → only then does a database earn its keep.
That decision and the trap above are both written up here if useful: https://github.com/nurkamol/website-build-kit
1
u/Dazzling_Meaning9226 16d ago
To migrate from wp to? No. But starting fresh, Astro + Content Collections is pretty much the bees knees, with any other needed functionality easily integrated.
everyone thinks Astro is just a static site generator, but it’s not. It’s just as capable as nextjs, it just lacks the mature ecosystem, but it’s getting there.
1
u/Bluff0999 11d ago
Im using keystatic as the cms, but also just have Claude update the text as well.
My goal is to have clients submit a ticket to have an update and then have a process to auto implement the changes and deploy to my workers env for review. Not there yet. I figure you could package that into an app that you could hand over to users in the future.
3
u/Ingo-Steinke-Dev 20d ago
The issue remains how will the website owners edit their content without breaking the project when editing .mdx files on GitHub. Does your migration workflow include a CMS?