Migrating from Heroku to Hatchbox (easier than you think)

#ruby-on-rails #heroku #hatchbox

by Stuart Yamartino

I have been using Heroku for the last decade and it has served me well. At the time it was released it was pretty revolutionary and The Twelve-Factor App principals were ahead of it’s time. However, Salesforce bought Heroku back in January 2011 (almost 15 years ago) and the platform has hardly evolved since. It feels like it has been in maintenance mode for years. That stagnation shows up in the pricing, too; what felt right for 2011 no longer makes sense in 2025.

Pricing aside, Heroku is strict about its dynos and you don’t get full server access which makes it hard matching versions of Ruby or Node with the buildpack configuration and can turn into a puzzle.

Meanwhile, tools like Kamal have matured and providers like Hetzner make cheap, powerful servers easy to access. I have been weighing alternatives to Heroku for a few years. Kamal is appealing, but I still like having a slick Heroku-style UI for configuring my apps.

With all that in mind, I decided to try Hatchbox. I kept seeing people rave about it, and knowing that Chris Oliver from GoRails built it gave me confidence it was worth testing. I used Laravel Forge back when I shipped Laravel apps a decade ago, and Hatchbox immediately felt familiar in the best ways.

Long story short: I switched all of my apps from Heroku to Hatchbox in a single day and came away impressed. I deployed a very modern app—Friends Weekly—running Rails 8.1 and Ruby 3.4, and it worked without a hitch. I also deployed a slightly older app—Bootstrap Email—running Rails 6 and Ruby 2.7, and it worked on the first try. I honestly couldn’t believe it just worked. I was struggling to even get the app running on my laptop or on a newer Heroku stack, yet Hatchbox handled it flawlessly. I was extremely impressed and wanted to share the migration process in case it helps others do the same.

Here are the steps we will go through to set up and migrate from Heroku to Hatchbox:

  1. Set Up Accounts
  2. Create Hatchbox Cluster
  3. Create Your App
  4. Starting to Migrate
  5. DNS
  6. Set up SSH
  7. Connect to Old and New DB with TablePlus
  8. Maintenance Mode
  9. Backup Heroku DB
  10. Restore to Hatchbox DB
  11. Bonus Features

Set Up Accounts

  1. Create your Hatchbox account.
  2. Create your Hetzner account, which you will use to provision servers. Hatchbox works with several VPS providers, but Hetzner is popular and very inexpensive compared to other options.

Create Hatchbox Cluster

  1. In Hatchbox, go to Servers, click New Cluster, and select Hetzner.
  2. You will need a Hetzner API token. In the Hetzner Console, select your Default project, choose Security in the left nav, switch to the API Tokens tab, and click Generate API Token. Give it Read & Write access.
  3. Copy that token back into Hatchbox and create the cluster.
  4. For my apps I selected Web Server, Cron, Background Worker, and PostgreSQL roles, but pick what your Rails app needs.

Create Your App

  1. In Hatchbox, open Apps and click New App.
  2. Select the new cluster, name your app, and click Create App.
  3. Connect to your repository. I used GitHub, which also makes auto-deploys easy to configure later.

Starting to Migrate

DNS

  1. Go into Domains & SSL and add your site’s domain name. Hatchbox will generate a domain and IP address pair.
  2. Update your DNS provider to point the domain to the new Hatchbox IP instead of the Heroku record.
  3. Your domain now points to the app running on Hatchbox and Hetzner, while still using the Heroku database under the hood.

Set up SSH

Connect to Old and New DB with TablePlus

Maintenance Mode

Backup Heroku DB

Restore to Hatchbox DB

Bring Back the App

Bonus Features

One of the best things about Hatchbox is the flat fee per server. You get access to every feature, unlike Heroku where only certain premium dynos or database tiers unlocked the good stuff.

One of my favorite features is continuous database backups to S3, R2, or any compatible storage service. Since the database is unmanaged, having an automated safety net matters. I set mine to back up the database daily to a Cloudflare R2 bucket that keeps 30 days of history and automatically prunes older backups so I am not paying for stale data. Each database gets its own subfolder, so I use one R2 bucket to backup all of my app databases in one place.

Another feature I appreciate is Cron Jobs. I used to lean on the Heroku Scheduler add-on to run scripts cheaply, but it was pretty limited. Hatchbox gives you full cron support, so migrating any scheduled tasks from Heroku is easy and you get complete control over timing and frequency.

Thank you to Chris Oliver for not only creating a great product, but also answer my questions on X and making me excited about my Rails servers again!