Migrating from Ghost: The Honest Guide (2026)
Exporting the JSON, mapping content, protecting rankings — and the honest case for staying
Nobody migrates off Ghost because the editor is bad — it's one of the best writing surfaces in any CMS. Teams migrate because they've outgrown the publication-only shape: they need pages that aren't posts, a real roles system, custom content on a server they already run, or they're just tired of paying Ghost(Pro) for a blog that gets 4 posts a month.
This guide covers the actual mechanics: exporting the Ghost JSON, mapping posts/tags/authors into a new CMS, the redirect plan that protects your rankings, and the honest part — what you lose when you leave Ghost, especially if you run a paid newsletter.
Disclosure: I work on UnfoldCMS, the worked example in this guide. There's no one-click Ghost importer in UnfoldCMS — the migration runs through the admin REST API or by hand, and I'll show exactly what that looks like. For some Ghost users (paid newsletters in particular), my honest advice is: stay.
TL;DR — when migrating from Ghost makes sense
Migrate from Ghost when you need more than a publication: arbitrary page types, finer permissions, full server control, or freedom from the Ghost(Pro) subscription. Don't migrate if your revenue runs through Ghost's members and paid subscriptions — that machinery is Ghost's core strength and no general-purpose CMS replaces it cleanly.
Quick decision table:
| Your situation | Verdict |
|---|---|
| Free blog/publication, self-hosted Ghost, tired of Node ops | Migrate — good fit |
| Ghost(Pro) bill growing, content is just posts + pages | Migrate — straightforward |
| Paid newsletter with Stripe subscriptions through Ghost | Stay on Ghost |
| Need custom content types, dashboards, or app features around the blog | Migrate — Ghost will keep fighting you |
| Happy with Ghost, just curious | Stay; bookmark this for later |
For the wider comparison of where to go, see Best Ghost Alternatives in 2026 and the head-to-head UnfoldCMS vs Ghost.
What's actually in a Ghost export (and what isn't)
Ghost gives you one JSON file from Settings → Labs → Export your content. It contains posts, pages, tags, and users — but not your images, not your members list, and not your theme. Plan for three separate exports: the JSON, the members CSV, and a copy of content/images from the server.
The JSON structure is a single db[0].data object with arrays you'll care about:
posts— both posts and pages (atypefield distinguishes them). Each hastitle,slug,html,feature_image,published_at,status, pluscustom_excerptand meta fields.tagsandposts_tags— tags plus the pivot linking them to posts.users,posts_authors— author profiles and their post assignments.
Three things the JSON does not include:
- Images.
feature_imageand inline<img>tags reference/content/images/...paths. Self-hosting?scpthe folder. On Ghost(Pro)? You'll script a download pass over those URLs. - Members. Export them separately from Members → Export all members (CSV with email, name, subscription status, labels).
- Newsletter analytics, email history, and Stripe linkage. These don't export in any usable form. More on that below — it's the deal-breaker section.
One pleasant surprise: Ghost stores rendered HTML alongside its internal Lexical/Mobiledoc format. You can ignore the editor-internal format entirely and import the html field straight into any CMS that accepts HTML bodies. That removes the single nastiest step most CMS migrations have.
Mapping Ghost concepts to the new CMS
Ghost's content model is small, which is exactly why this migration is easier than a WordPress one (compare with our WordPress migration guide). Here's the full mapping using UnfoldCMS as the worked example — adapt the right column for Strapi, Payload, or whatever you've picked:
| Ghost concept | UnfoldCMS equivalent | Notes |
|---|---|---|
Post (type: post) |
Post (content_type: post) |
html → body, custom_excerpt → short_description |
Page (type: page) |
Post (content_type: page) |
Same model, different type — convenient here |
| Tag | Category | Many-to-many, same shape as posts_tags |
Internal tag (#hidden) |
Drop, or map to a flag | Internal tags are workflow metadata, not taxonomy |
| Author / staff user | User with role | Map Ghost roles (Author/Editor/Admin) to RBAC roles |
feature_image |
featured-image media collection |
Re-upload; conversions to WebP happen on import |
meta_title / meta_description |
seo_title / meta_desc |
Carry these over — don't let the new CMS regenerate them |
published_at + status |
posted_at + is_published |
Future-dated posts keep working via scheduled publishing |
redirects.yaml |
Redirect manager (CSV import) | Covered in the redirect section |
| Members + subscriptions | No equivalent | The honest gap — see "What you lose" |
| Newsletter sending | No equivalent | Hand off to Buttondown/Mailcoach/Listmonk |
Two mappings deserve a flag. Ghost's primary-tag concept (first tag = primary) has no special meaning in most CMSs — pick the category order deliberately. And Ghost's per-post code injection maps to a code-snippets feature only in UnfoldCMS Pro, not Core — check tier pages before assuming.
The migration, step by step
The whole thing is six steps: export everything, stand up the new CMS, write a small import script against the admin API, move images, wire redirects, then cut DNS over. For a typical Ghost blog (50–300 posts, a handful of tags), budget 2–4 days of focused work, not weeks.
- Export the three artifacts. Labs JSON export, members CSV, and the
content/imagesdirectory. Do this twice — once now for development, once again the day of cutover so you don't lose posts published in between. - Stand up the new CMS and model the basics. Create the categories (from Ghost tags) and user accounts (from Ghost staff) by hand — there are usually fewer than 20 of each, and hand-creating them lets you clean up six years of tag sprawl. Most Ghost blogs have 30% dead tags; don't port those.
- Write the import script. Parse
db[0].data.posts, skip drafts you don't want, and POST each one to the CMS's write API. With UnfoldCMS that's a Sanctum token plus the admin endpoints:POST /api/v1/admin/postswithtitle,slug,body(Ghost'shtmlfield as-is),short_description,seo_title,meta_desc, andposted_at. Category attachment uses the same CRUD surface. Expect 100–200 lines of Node or PHP, mostly field renaming. Rate limits apply (30 req/min on the admin scope), so a 300-post import takes about 10 minutes with a polite sleep between calls. - Move the images. Upload featured images to the new media library and rewrite inline
/content/images/...URLs in post bodies to their new locations. This is the most tedious step — a find-and-replace pass over the HTML before import handles 90% of it. - Import redirects. Build the old-URL → new-URL map (next section) and load it. UnfoldCMS takes a CSV straight into the redirect manager; other CMSs vary between config files and nginx rules.
- Dry-run, verify, cut over. Crawl your new staging site against your live Ghost sitemap — every URL in the old sitemap should return 200 or 301 on the new host. Then switch DNS, keeping Ghost running (paused, not deleted) for at least one billing cycle as rollback.
If you want the framework-agnostic version of this checklist, the CMS migration guide for developers walks the same steps without the Ghost-specific parts.
Want to test the import target before committing? Spin up the UnfoldCMS demo and poke at the admin API with your real export — it's the fastest way to find mapping surprises early.
Redirect strategy: keep your rankings intact
Ghost serves posts at root-level /{slug}/. Most CMSs default to /blog/{slug} or another prefix, which means every single post URL changes unless you act. You have two options: configure the new CMS to serve posts at root level, or 301-redirect every old URL. Either works; pick one and be complete about it.
Option one is cleaner when available. UnfoldCMS lets you set the post URL pattern in admin (posts can live at /{slug} instead of /blog/{slug}), which makes most redirects unnecessary — old Ghost URLs just keep resolving. Slug history covers you afterward too: rename a slug post-migration and the old one still resolves.
Option two — the redirect map — you'll need regardless for the URLs that have no equivalent:
/tag/{slug}/→ your new category URLs (301 each one; tag pages collect real backlinks)/author/{slug}/→ author profile pages, or the blog index if you drop author pages/rss/→ your new feed URL — do not forget this one; feed readers poll it forever- Anything in your existing Ghost
redirects.yaml— port those rules or you'll break URLs that were already redirected once
Generate the map by parsing your Ghost sitemap, then import it as CSV into the redirect manager. Use 301s for everything permanent; if you're staging a gradual move, 302s with an expiry date let temporary rules clean themselves up. After cutover, watch the redirect hit counts for a week — URLs with zero hits and URLs 404ing in your logs tell you what you missed.
Trailing slashes matter here: Ghost URLs end in /, and your new stack might not. Make sure your redirect rules and your web server agree on one canonical form, or you'll chain redirects (Ghost URL → slash-stripped URL → new URL) and leak link equity.
RSS and newsletter subscribers: the handoff
Your RSS subscribers come along for free if you 301 /rss/ to the new feed — feed readers follow redirects. Your email subscribers don't: Ghost's newsletter sending doesn't exist outside Ghost, so the members CSV must move to a dedicated email tool, and you should tell subscribers before the switch.
The concrete handoff:
- Export the members CSV (email, name, labels, subscription state).
- Import free subscribers into an email tool — Buttondown, Mailcoach, and Listmonk are the usual self-host-friendly picks. Filter out unsubscribed and bounced rows first; importing them tanks your sender reputation.
- Send one final email from Ghost announcing the move, so the first email from the new sender isn't a surprise that triggers spam reports.
- Wire new-post notifications. UnfoldCMS fires HMAC-signed webhooks on post publish — point one at your email tool's API and "new post → newsletter draft" keeps working. What it does not have is built-in email campaign sending; the newsletter module (Pro) manages subscribers and signup forms, not broadcast sends. Be honest with yourself about this gap before you commit.
Paid subscribers are a different story entirely — next section.
What you lose, and what you gain
You lose Ghost's members system, paid subscriptions, native newsletter sending, and the tight post-to-inbox publishing loop. You gain arbitrary content types, real RBAC, a redirect/SEO toolkit, an admin write API for automation, and a stack you fully own. Whether that trade is good depends entirely on whether your revenue flows through Ghost.
What you lose:
- Members and paid subscriptions. Ghost's Stripe integration, paywalled content, member portal, and tiered access are deeply Ghost-specific. No general-purpose CMS gives you this out of the box. Rebuilding it means Stripe + custom gating code — weeks of work, and you become the maintainer.
- Native newsletter sending. Covered above. You'll run a second tool.
- Ghost's editor. Whatever you move to, the writing experience will feel different. Modern admin editors are good; Ghost's is still the benchmark for pure writing flow.
What you gain (UnfoldCMS numbers, June 2026):
- Posts and pages and landing pages in one model, plus scheduled publishing that runs on a plain cron — shared hosting works, no Node process to babysit.
- Threaded comments in Core, without Disqus or a third-party embed.
- An SEO toolkit Ghost makes you work for: sitemap and robots.txt generated dynamically, JSON-LD helpers, a 301/302 redirect manager with CSV import and hit tracking, and slug history.
- A versioned REST API (
/api/v1/*) with public read endpoints and token-authenticated admin write — the thing that made the scripted import in step 3 possible keeps paying off for any automation after. - Role-based access control beyond Ghost's four fixed roles.
What you should not expect from UnfoldCMS, so there are no surprises: no GraphQL, no official npm SDKs (plain fetch() against the REST API), no post revisions, no multi-language content, and — repeating it once more — no one-click Ghost importer. The import is a script you write against the API. It's a small script, but it's yours.
When you should NOT migrate
If Ghost is your revenue engine, stay. A paid newsletter with even 50 paying members has Stripe subscriptions, paywall rules, and member-auth flows wired into Ghost's core — migrating means rebuilding a billing product, not moving a blog. The CMS bill you'd save is a rounding error against that engineering cost and churn risk.
Stay on Ghost when:
- You run paid subscriptions through Ghost. This is the hard no. Migrating breaks the member portal, the paywall, and the subscription lifecycle in one move. The teams I've seen attempt it spent 6+ weeks on the rebuild and lost subscribers in the transition.
- The newsletter is the product. Even free newsletters: Ghost's publish-to-inbox loop is genuinely better than CMS + separate email tool, and the switch always costs some list health.
- You publish a lot and the editor is why. If your writers love the Ghost editor and your content is plain posts, the migration buys you flexibility you may never use.
- Your Ghost(Pro) bill is small. Under ~$30/month, the engineering time to migrate costs more than years of subscription. Same math as every CMS migration.
Migrate when the opposite holds: content beyond posts, server you control, automation needs, no paid-member machinery, and a bill or ops burden that actually bothers you.
FAQ
How do I export all my content from Ghost?
Settings → Labs → Export your content gives you a single JSON file with posts, pages, tags, and users. Images are not included — copy content/images from your server or script a download. Members export separately as CSV from the Members screen. Take a fresh export on cutover day.
Does UnfoldCMS have a Ghost importer?
No — there's no one-click Ghost importer. Migration runs through the admin REST API (POST /api/v1/admin/posts with a Sanctum token) or manual entry. Since Ghost exports rendered HTML per post, the import script is mostly field renaming: typically 100–200 lines of code for a complete blog.
Will I lose my Google rankings when I migrate from Ghost?
Not if URLs are handled. Either configure the new CMS to serve posts at Ghost's root-level /{slug} pattern, or 301-redirect every old URL — posts, tag pages, author pages, and /rss/. Crawl your old sitemap against the new site before cutover; every URL should answer 200 or 301.
Can I move my Ghost paid subscriptions to another CMS?
Practically, no. Stripe customers export, but Ghost's paywall, member portal, and subscription lifecycle don't transfer to any general-purpose CMS. You'd rebuild billing and content gating from scratch. If paid subscriptions are live revenue, the honest recommendation is to stay on Ghost.
Bottom line
Migrating from Ghost is one of the easier CMS migrations — small content model, HTML in the export, predictable URLs. The work is a weekend-to-a-week of scripting, and the decision is simple: free publication that's outgrown Ghost's shape → migrate; paid newsletter business → stay and don't look back.
If you're in the first group, compare UnfoldCMS against Ghost feature-by-feature, then check pricing — one-time, not a subscription — and run your real export against the demo before you commit to anything.
Sources & methodology
- Ghost export format — verified against Ghost 5.x Labs JSON exports (the
db[0].datastructure withposts,tags,users, and pivot arrays) and Ghost's official export/import documentation, June 2026. - Migration time estimates — based on completed Ghost-to-UnfoldCMS migrations of 50–300-post blogs plus conversations with publishers who moved to other self-hosted CMSs.
- UnfoldCMS feature claims — verified against the codebase truth doc (June 2026):
/api/v1/*REST API with admin write CRUD and Sanctum tokens, HMAC-signed webhooks, redirect manager with CSV import and optional expiry, slug history, scheduled publishing, JSON-LD helpers, Core-tier comments, WebP media conversions. Gaps stated (no Ghost importer, no GraphQL, no revisions, no email campaigns) verified against the same source. - Email tool suggestions (Buttondown, Mailcoach, Listmonk) reflect common self-hosted-friendly picks as of June 2026; evaluate current pricing and deliverability yourself.
Free & Open Source
Own your CMS. No subscriptions.
Unfold CMS is free to download and self-host. Built on Laravel + React, full source code included.
Share this post: