Migrating from Ghost: The Honest Guide (2026)

Exporting the JSON, mapping content, protecting rankings — and the honest case for staying

June 28, 2026 · 13 min read
Migrating from Ghost: The Honest Guide (2026)

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 (a type field distinguishes them). Each has title, slug, html, feature_image, published_at, status, plus custom_excerpt and meta fields.
  • tags and posts_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:

  1. Images. feature_image and inline <img> tags reference /content/images/... paths. Self-hosting? scp the folder. On Ghost(Pro)? You'll script a download pass over those URLs.
  2. Members. Export them separately from Members → Export all members (CSV with email, name, subscription status, labels).
  3. 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) htmlbody, custom_excerptshort_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.

  1. Export the three artifacts. Labs JSON export, members CSV, and the content/images directory. Do this twice — once now for development, once again the day of cutover so you don't lose posts published in between.
  2. 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.
  3. 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/posts with title, slug, body (Ghost's html field as-is), short_description, seo_title, meta_desc, and posted_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.
  4. 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.
  5. 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.
  6. 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:

  1. Export the members CSV (email, name, labels, subscription state).
  2. 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.
  3. 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.
  4. 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].data structure with posts, 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:

Discussion

Comments (0)

Leave a Comment

Please log in to leave a comment.

Don't have an account? Register here

No comments yet. Be the first to share your thoughts!

Keep Reading

Related Posts

Back to all posts