How to Migrate from Substack to Ghost

Move your Substack publication to Ghost without losing subscribers. Step-by-step guide covering content, paid members, Stripe, and what to watch for.

Luxe Themes Updated 11 min read

Why Publishers Leave Substack

Substack takes 10% of your subscription revenue plus Stripe fees. On Ghost, the platform fee is 0%.

At $5,000/month in revenue, Substack takes $500 every month. On Ghost, that $500 stays in your account. Over a year, that is $6,000 in savings. It would cover Ghost(Pro) Publisher for over 17 years.

The fee is not the only reason people move. Substack’s design is the same for every publication. Its SEO controls are minimal. And on Ghost, your subscribers live on your platform, on your terms.

This guide covers each step of moving from Substack to Ghost: your content, your subscribers, and, most importantly, your paid memberships. It also covers the errors people most often hit along the way, and what to do after the move.

What Transfers

Ghost has official Substack migration support. The import tool handles:

ContentTransfers?Notes
PostsYesAll published and draft posts
ImagesYesInline images from posts
Free subscribersYesEmail addresses and names
Paid subscribersYesVia shared Stripe account (see below)
Post datesYesOriginal publication dates preserved
Post URLsYesSlugs preserved to maintain links

What Does Not Transfer

ContentWhy Not
Substack NotesNotes are Substack-specific social features with no Ghost equivalent
Substack ChatChat history stays on Substack
Subscriber activity dataOpen rates, click history from Substack are not exported
Recommendation listsYour Substack recommendation network does not migrate
Custom subdomainYour .substack.com URL stays with Substack
Profile customizationsBio, avatar, and profile settings need to be recreated
Apple in-app subscribersReaders who subscribed through the Substack iOS app pay Apple, not your Stripe account — there is no Stripe customer to migrate (see troubleshooting below)

The Stripe Connection: Key to Paid Migration

Both Substack and Ghost take payments through Stripe. Because they share that layer, paid subscribers can move across without re-subscribing. Handling your Stripe account correctly is the most important part of this migration.

How It Works

  1. Substack connected to your Stripe account when you set up paid subscriptions
  2. Ghost connects to the same Stripe account
  3. Ghost matches Substack subscribers to their Stripe customer IDs
  4. Existing subscriptions continue billing through Ghost instead of Substack

The Critical Step: Disconnect Substack from Stripe

After connecting Ghost to your Stripe account, you must disconnect Substack. If you do not:

  • Substack continues receiving its 10% fee on existing subscriptions
  • You may have two platforms trying to manage the same Stripe subscriptions
  • Subscribers could be double-billed

Contact Substack support to request disconnection from your Stripe account. This is not self-service. You need Substack to disconnect on their end.

Statement Descriptor

The statement descriptor is the name subscribers see next to the charge on their credit card statements. After migration, check it in your Stripe public details settings. It might still say “Substack” from the original setup. Update it to your publication name so subscribers see the correct name.

Step-by-Step Migration

Step 1: Set Up Ghost

Before migrating, have your Ghost site ready:

  1. Sign up for Ghost(Pro) Publisher ($29/month) or set up a self-hosted instance
  2. Choose and install your Ghost theme
  3. Configure basic settings (site title, description, navigation)
  4. Connect your Stripe account to Ghost (Settings → Membership → Connect to Stripe)

Use the same Stripe account that is connected to your Substack. This is essential for paid subscriber continuity.

Step 2: Export From Substack

  1. In Substack, go to Settings → Export Data
  2. Download your content export (posts and subscriber data)
  3. Also download your subscriber CSV from the Subscribers tab

Note: Substack’s CSV exports can be inconsistent. Some exports are missing Stripe customer IDs for paid subscribers. Ghost’s import tool handles this by matching subscribers through the shared Stripe account. Even so, verify your paid subscriber count after import.

Step 3: Import Into Ghost

  1. In Ghost Admin, go to Settings → Advanced → Import/Export
  2. Upload your Substack export zip — Ghost detects it and runs the Substack importer
  3. Import your free and paid subscriber CSVs separately via Members → Import
  4. When importing subscribers, apply a label such as substack-import. You will need it later for the welcome email (see troubleshooting)

Ghost’s Substack importer is built for this job. It converts posts, preserves dates and slugs, and matches paid subscribers to Stripe. Two ordering rules matter, and many failed migrations come down to one of them. Connect Stripe before importing paid subscribers, and create your paid tiers before the import too. Otherwise Ghost cannot match subscriptions and skips those members.

Step 4: Verify Content

After import, check:

  • Open five to ten posts and verify content, images, and formatting
  • Verify post dates are correct
  • Check that post slugs match your Substack URLs (they should)
  • Confirm all images load properly

Step 5: Verify Subscribers

In Ghost Admin, check the Members section:

  • Total members: Should match your Substack subscriber count
  • Paid members: Should match your Substack paid subscriber count
  • Stripe connection: Verify paid members show correct Stripe subscription status

If paid subscriber counts do not match, check your Stripe Dashboard for subscriptions that may not have been matched. Ghost support can help resolve discrepancies.

Step 6: Set Up Your Newsletter

Configure your Ghost newsletter settings:

  1. Go to Settings → Newsletters
  2. Set your sender name and email
  3. Configure email design (header image, fonts, colors)
  4. On Publisher plan: set up a custom sending domain

Step 7: Disconnect Substack from Stripe

This is the step you cannot skip:

  1. Contact Substack support requesting disconnection from your Stripe account
  2. Verify in your Stripe Dashboard that Substack’s application is no longer connected
  3. Confirm Ghost is the only platform connected to your Stripe subscriptions

Step 8: Redirect Your Domain

If you were using a custom domain on Substack:

  1. Update DNS to point to your Ghost site
  2. Remove the domain from Substack’s settings
  3. Add the /p/ redirect rule so old Substack links keep working (next section)

If you were on a .substack.com URL:

  1. There is no way to redirect from your Substack URL
  2. Publish a final post on Substack pointing readers to your new Ghost URL
  3. Consider keeping the Substack profile page active with a link to your new site

Step 9: Notify Your Subscribers

Send a newsletter through Ghost to all subscribers announcing the move:

  • Explain what changed (new platform, same content)
  • Note that their subscription is unaffected (billing continues normally)
  • Highlight any new features (archive on your domain, improved design)
  • Ask them to update any bookmarks to your new URL

Troubleshooting: The Errors Migrators Hit Most Often

These are the problems that come up most often in Substack-to-Ghost migrations, with the fixes that resolve them.

”File Type Not Allowed” When Uploading the Export

You upload the zip straight from Substack and Ghost rejects it with “File Type Not Allowed”. The export is not broken. This is a Windows quirk. Every file carries a type label, called a MIME type, that tells software what kind of file it is. Windows labels zip files as application/x-zip-compressed, while Ghost’s importer expects application/zip, so a valid export gets bounced.

Fixes, in order of effort:

  1. Unzip and re-zip the export, then upload again. Repacking often normalizes the file type.
  2. Upload from a different OS. The same zip that fails on Windows imports cleanly from macOS or Linux.

”Could not find Stripe customer” on Paid Subscriber Import

Your paid CSV import fails member by member with “Could not find Stripe customer”. Each row of your CSV carries a Stripe customer ID (stripe_customer_id). Ghost looks that ID up in the Stripe account it is connected to, and it is not finding it. The usual causes:

  • Ghost is connected to a different Stripe account than the one Substack billed through. This is easy to do if Stripe has split your business into multiple accounts. Check which account holds the subscriptions before connecting.
  • Wrong mode. Stripe has a test mode and a live mode. Ghost is connected in test mode while the customers live in live mode.
  • Missing tiers: Ghost needs your paid tiers created before the import, or it cannot match subscriptions to a product.
  • Substack was disconnected from Stripe too early. If Substack disconnects mid-migration, you can lose every imported paid member. Import first, verify counts, then have Substack disconnect.

The order that works: same Stripe account → live mode → tiers created → import paid CSV → verify → disconnect Substack.

Substack serves posts at yourdomain.com/p/post-slug. Ghost serves them at yourdomain.com/post-slug. On a custom domain, every old link, search result, and social share hits a 404 until you add a redirect. Ghost manages redirects through a file called redirects.yaml, which you upload under Settings → Labs. This is Ghost’s official rule for Substack:

301:
\/p\/(?![0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})(.*): /$1

The long middle part matters. Ghost’s own editor previews live at /p/<uuid>, so a simpler /p/(.*) rule breaks post previews in Ghost Admin. Many people hit that before the official rule added the UUID exclusion. Use the rule as written.

On a .substack.com address there is nothing to redirect, because you never controlled that domain. Publish a final Substack post pointing to your new site instead.

Images Still Hosted on Substack’s CDN

Substack serves its images from a content delivery network, or CDN, at substackcdn.com. Open a migrated post and inspect an image. If the URL points there, your “migrated” images still live on Substack’s servers. It works today, but your content now depends on a platform you just left. If that account or CDN path ever goes away, your archive loses its images.

The fix depends on where you are in the migration:

  • Before/during migration: use Ghost’s open-source migrate CLI. Running migrate substack with --scrape all (or --scrape assets) downloads images into the import zip so they upload to your own site
  • Already imported: there is no one-click re-host. The usual approach is a script against the Ghost Admin API: find Substack image URLs in post HTML, download each image, upload it via the API, and rewrite the post. Ghost(Pro) customers can ask Ghost’s migrations team for help instead.

Either way, verify by spot-checking image URLs. They should start with your domain and /content/images/.

Welcome Emails Don’t Fire for Imported Members

Ghost’s welcome emails and welcome-flow automations trigger on signup, meaning someone typing their address into your site. Members who arrive via CSV import get nothing. This catches many migrators out: your entire migrated audience silently skips your onboarding.

The workaround is the label from Step 3: filter Members by your substack-import label and send a one-off welcome post or email to exactly that group. It doubles as your migration announcement.

Apple In-App Subscribers Cannot Be Migrated

Since Substack adopted Apple’s in-app purchase system for iOS subscriptions in 2025, readers who subscribed inside the iPhone app pay Apple. Their billing never touches your Stripe account. With no Stripe customer record, Ghost has nothing to match, and no migration path exists.

What you can do: export their emails, import them as free members, and run a re-subscribe campaign with a discount offer for former paid readers. Expect to lose some. This is a strong argument for migrating before your iOS-subscriber share grows.

Substack Content Formatting Issues

Substack’s content format is simpler than Ghost’s. Some formatting may not convert perfectly:

  • Buttons: Substack subscribe buttons become text links
  • Embeds: Some third-party embeds may need to be re-added
  • Image captions: May need reformatting

Ghost’s editor builds posts out of blocks it calls cards. Once you know your way around them, these fixes are quick. Our Ghost editor guide walks through buttons, embeds, and captions.

Email Deliverability After Migration

Your first few Ghost sends may have lower deliverability while email providers learn your new sending setup. To improve it:

  • Set up the email authentication records (SPF, DKIM, and DMARC) for your custom sending domain
  • Start with your most engaged subscribers
  • Monitor open rates and check for spam folder placement
  • Gradually increase send volume

After Migration

Set Up SEO

Your Substack posts had minimal SEO optimization. Now on Ghost, you can:

  • Add custom meta titles and descriptions to your most important posts
  • Verify your sitemap at yourdomain.com/sitemap.xml
  • Submit your sitemap to Google Search Console
  • Set up proper canonical URLs

Every post is now a permanent, indexable web page on your domain. That builds search traffic Substack never provided.

The Revenue Math

Calculate your annual savings:

Monthly RevenueSubstack Fee (10%)Ghost(Pro) PublisherAnnual Savings
$1,000$100/mo$29/mo$852/year
$3,000$300/mo$29/mo$3,252/year
$5,000$500/mo$63/mo$5,244/year
$10,000$1,000/mo$88/mo$10,944/year

The savings grow with your revenue. Because Ghost’s pricing is fixed, growing does not raise your platform fees.

Your New Publication Identity

The most visible change after migration is design. Every Substack looks the same. Your Ghost publication looks like yours.

Rune Ghost theme with dark mode and featured post highlights

If you want your publication to look like your own after the move, our themes include dark mode, multilingual translations, and membership pages, starting at $69.

See the best Ghost themes for newsletters →

That is the whole move: your content, subscribers, and paid memberships are on Ghost, and Substack is disconnected from Stripe. Day one after migrating is picking your look. The best Ghost themes guide is a fast way to choose.

If you are still weighing the move, our Ghost vs Substack comparison covers fees, features, and ownership. If your content lives on WordPress rather than Substack, the WordPress to Ghost migration guide walks that path. The importer is different; the destination is the same.

Frequently Asked Questions

Do my subscribers transfer from Substack to Ghost?
Yes. Ghost has official Substack migration support, and its import tool transfers free subscribers (email addresses and names) along with paid subscribers. It also carries over all published and draft posts, inline images, original post dates, and slugs so your existing links keep working. After import, verify your total member count in the Ghost Admin Members section.
Will my paid subscriptions keep billing without re-subscribing?
Yes. Both Substack and Ghost use Stripe, so connecting Ghost to the same Stripe account lets it match subscribers to their Stripe customer IDs and continue billing them automatically. No one has to re-subscribe. Afterward you must contact Substack support to disconnect them from Stripe, or Substack keeps taking its 10 percent and subscribers risk being double-billed.
How do I make sure no paid subscribers get lost in the move?
After importing, open the Members section in Ghost Admin and confirm total and paid member counts match Substack, since Substack CSV exports can be inconsistent and sometimes omit Stripe customer IDs. If counts differ, check your Stripe Dashboard for unmatched subscriptions, manually add those members in Ghost, and link them to their Stripe subscription.
What does not transfer when I migrate to Ghost?
Several Substack-specific items stay behind. Notes and Chat history do not migrate, and subscriber activity data like open and click history is not exported. Your recommendation lists, profile customizations such as bio and avatar, and your .substack.com URL also do not carry over. You will need to recreate profile settings and notify readers of your new Ghost address.
Why do I get a File Type Not Allowed error when importing my Substack export?
This is almost always a Windows problem, not a broken export. Windows labels zip files with the MIME type application/x-zip-compressed, while Ghost's importer expects application/zip, so a perfectly valid export gets rejected. Unzipping and re-zipping the file often fixes it; if not, upload the same zip from a Mac or Linux machine and it goes through.
How do I fix the Could not find Stripe customer error when importing paid subscribers?
Ghost throws this when it cannot find the customer IDs from your CSV in the Stripe account it is connected to. Connect Ghost to the exact same Stripe account Substack uses, in live mode, and create your paid tiers before importing the paid-subscriber CSV. If you have multiple Stripe accounts, check which one holds your Substack subscriptions before connecting.
Do subscribers who paid through the Substack iOS app transfer to Ghost?
No. Since Substack adopted Apple's in-app purchase system for iOS subscriptions in 2025, those readers pay Apple, not your Stripe account. Because they have no Stripe customer record, Ghost has nothing to match, and their subscriptions cannot be migrated. Import them as free members and invite them to re-subscribe directly, ideally with a discount offer.
Why did imported members not receive my Ghost welcome email?
Ghost's welcome emails and welcome-flow automations only trigger when someone signs up through your site. Members added via CSV import or the API are skipped. The workaround: apply a label during the import, then send a one-off welcome post or email filtered to that label so migrated readers still get an introduction.

Keep reading