Migrating from Substack to Ghost: A Software Engineer's Perspective

Migrating from Substack to Ghost: A Software Engineer's Perspective
Photo by Jan-Niclas Aberle / Unsplash

I recently started a 14-day trial on Ghost and migrated my articles from Substack. In this post, I'll walk through why I originally chose Substack, what drove me to explore Ghost, and how the two platforms compare after migration.

Why I Originally Chose Substack

When I first decided to start writing about software engineering, I wasn't aware of Ghost. My options came down to three platforms: Medium, Dev.to, and Substack.

Medium didn't suit my needs. Theme customization is extremely limited, the site feels unnecessarily heavy, and the constant popups degrade the experience for both readers and writers. More fundamentally, Medium is platform-centric — writers get a profile handle rather than a standalone website. That model works well for building an audience, but since my blog spans everything from technical deep-dives to personal reflections, I wanted a space that felt like my own.

Dev.to shares all of Medium's shortcomings and adds two more. Its interface is cluttered, which clashes with my preference for minimalist design. It's also saturated with low-effort LLM content right now, and I didn't want my work mixed in with that.

That left Substack as the only viable option at the time. It gave me a customizable website and a decent writing experience — or so I thought.

Where Substack Falls Short

Substack is arguably the worst platform for software engineering content, and the reason is simple: it doesn't support code blocks. This is a well-documented complaint in the community, and the Substack team has consistently chosen not to address it. My workaround was rendering snippets with highlight.js and uploading them as screenshots — a solution that bloated page size and made it impossible for readers to copy code.

Cover image management was another pain point. Ghost lets you search Unsplash directly from the editor, automatically handles attribution and source links, and provides built-in tools for filtering, cropping, and resolution adjustment. Substack offers none of this. To maintain a consistent black-and-white aesthetic across my site, I had to manually process every image through Affinity Photo. Most Unsplash images ship at 4K+ resolution, and without a quick way to downscale them, my archive pages became painfully slow to load. Attribution was also neglected — not out of intent, but because the process was too tedious to sustain.

The Migration Process

The migration itself was straightforward. I followed Ghost's developer documentation and everything transferred cleanly. Posts imported correctly, and Substack-specific components like embedded links and subscribe buttons were automatically converted to their Ghost equivalents.

One minor suggestion for the Ghost team: the import process creates two internal tags for migrated posts that I had no use for. An option to disable automatic tag creation during import would be a welcome addition.

After the migration, I went through each post to update images with proper resolution and attribution via Ghost's Unsplash integration. I also simplified my tag structure to reduce duplicate posts appearing across different tag pages.

Rough Edges in Ghost

Ghost isn't without its own issues. Here's what I've encountered so far:

Safari support is lacking. Ctrl+click / Cmd+click on the posts tab in the admin panel doesn't work in Safari, though it functions fine in Chrome. At this point, I'm fairly confident no one on the Ghost team uses Safari as their primary browser.

Image save state is unreliable. After modifying and saving an image, the "Update" button remains active while the image is still being processed in the draft. Clicking it prematurely results in the change not being persisted. The button should be disabled until the image has fully loaded.

The default theme (Casper) has layout bugs. Images overflow horizontal margins, which shouldn't be happening in a flagship theme.

The editor has a steeper learning curve than Substack's. The / command palette, while powerful, isn't intuitive for less technical users. Adding a subscribe button, for instance, requires creating a snippet first — there's no direct insertion option.

Minor UX issues persist. After deleting an internal tag, the UI redirects to the public tags tab instead of staying on the internal tags tab. Also, there's no way to import pages (such as an About page) and comments — only posts.

Pricing is a concern. The Starter plan at $15/month feels steep, especially considering it doesn't even support paid subscribers. I'm comfortable paying for good software — I subscribe to Kagi Professional at $10/month and Claude Pro at $24 CAD/month, among others — but I'd find the Starter plan much easier to justify at $7–10/month. A student discount would also go a long way.

What's Next

I have 12 days left on my trial. During that time, I plan to publish at least three more articles to properly evaluate whether Ghost justifies its price tag. If it does, I'll commit fully and decommission my Substack. If it doesn't, I'll port the new articles back to Substack and move on.