How I moved my site from WordPress to Ghost in an afternoon
The actual process in 2026 using the official Ghost plugin. What works, what breaks, and how to stop the migration eating your search rankings.
I expected this to take a weekend. It took an afternoon.
Most of what I'd read about WordPress to Ghost migrations was either ten years out of date or written by someone selling a paid migration service. The actual process in 2026 is genuinely fast for a typical blog. Here's what I did, what worked, and what broke. Skip to what broke if you want the honest part first.
Why I moved
I covered the long version of this in Ghost vs WordPress. Short version: my WordPress install had drifted into a stack of plugins I didn't choose. Yoast for SEO, Elementor for layout, Jetpack for the things Jetpack does, plus a security plugin to patch the security holes the other plugins introduced. Every one of them needed updates. Every update was a small risk.
Ghost is opinionated. There's no plugin marketplace because Ghost doesn't want one. That sounds like a flaw and is in fact why Ghost is good at the one thing it does.
The actual steps
Ghost maintains an official WordPress plugin that does almost all of the work. You don't need a paid service. The whole flow has four steps.
- Install the Ghost plugin in WordPress. Plugins, Add New, search "Ghost". The one you want is by "Ghost Foundation". Two minutes.
- Export. Tools, Export to Ghost. Review the prep notes. Click Download Ghost File. You get a ZIP with posts, pages, tags, authors, and image references. Sub-minute on a small blog.
- Import to Ghost. In Ghost admin, Settings, Labs, Import content. Upload the ZIP. The progress bar runs for a few minutes. You watch it and have a coffee.
- Set up redirects. Ghost admin, Labs, Redirects. Upload a
redirects.jsonfile mapping old WordPress URLs to new Ghost slugs. This is the bit most people skip and regret.
For a 200-post blog that took roughly 90 minutes including the redirect file. Most of that was me being slow about the redirect file because I wanted to get it right.
What broke
The Ghost importer is genuinely solid for everything that maps cleanly. Posts, pages, tags, authors, featured images, dates, slugs. Those all came across without me touching them.
What didn't come across cleanly:
- Categories became tags. Ghost doesn't have categories. The importer flattens them into tags and uses the first category as the primary tag. If your WordPress site had a meaningful category hierarchy, you lose the hierarchy. For most blogs this is fine. For a heavily-categorised site you'll want to clean up tags afterwards.
- Shortcodes died. Anything inside
[caption],[audio], or[code]became a literal string in the post body. Page-builder shortcodes from Elementor and Divi ([vc_*]and[et_*]) got worse. They're effectively unparseable garbage in Ghost. If your old site used a page builder, you'll be doing manual cleanup. - Plugin-generated content didn't render. TablePress tables, gallery plugins, anything where the content was held in plugin-specific shortcodes. Same problem as above.
- Hundreds of images were slow. The importer has to download each image from your old WordPress server and re-upload it. On a fibre line that's still ten minutes for a thousand-image archive.
- Imports over 100MB timed out. Ghost recommends keeping the import file under 100MB. If yours is bigger, split into chunks of about 40MB and import in sequence. Annoying but doable.
- One ancient PHP gotcha. If your WordPress was running on PHP 7 the export can produce invalid dates and every post lands on the same day. Upgrade to PHP 8 first if you can. This bit me on a backup site I tested with.
That list looks long but most of it doesn't apply to most blogs. If your WordPress site is mostly posts with images and tags, you'll hit none of it. If you've been on a page builder for years, set aside an extra day.
The redirects step that everyone skips
WordPress and Ghost don't share URL structures. WordPress defaults to /2024/03/15/post-slug/. Ghost defaults to /post-slug/. If you don't redirect, every link to your old posts in Google's index returns a 404 the day after you switch DNS.
Ghost's redirects.json is plain JSON. One entry per redirect, regex supported:
[
{
"from": "^/\\d{4}/\\d{2}/\\d{2}/(.*)$",
"to": "/$1",
"permanent": true
}
] That single regex covers the WordPress year-month-day URL pattern. If you used a different permalink structure, adjust accordingly. The 301 redirect tells Google the URL has moved permanently and the ranking transfers across over a few weeks.
What it felt like after
The first thing you notice is speed. Ghost loads. WordPress loaded eventually. The second thing is the editor. Ghost's writing UI is the closest thing to "stop fighting me" I've used. The third thing, eventually, is that you stop thinking about plugin updates. The site just sits there and works.
I lost a couple of pre-built page-builder pages in the move. The cleanup took an afternoon. Six months later I haven't missed them.
Where to go next
If you've got memberships and a paid newsletter, Ghost handles those natively (Stripe baked in, 0% take-rate beyond Stripe's own processing fees). If you also want to sell stickers, prints, digital downloads, or anything else physical or digital on top of the writing, that's where Ghost stops and where I built xVoid. Different post for that. The short version is in Why I built xVoid.
For now: if you're on WordPress and you've been thinking about this, the migration itself isn't the obstacle anymore. The Ghost plugin works. The afternoon is enough.