Bye Heroku, hey

Bye Heroku, hey

Migrate datastore for this blog’s comment system
Published November 30, 2022
I still remember the first time I deployed a database backed website with a single command, it completely blows my mind and the tool made it possible was Heroku. Nowadays when talking about containerization, Docker/k8s gets mentioned a lot, but the real pioneer in that space (PAAS) is Heroku, at least to me. It offloads the burden of provisioning (e.g. bins/libs installation), scaling (e.g. load balancing), dealing with security (e.g. tls/ssl termination) and a lot other chores from programmers, so that they only need to focus on building the app. However, Heroku recently (11/28) cancelled its free plan for all customers. As a result, I did a bit research to look for an alternative and came across another great tool -


One practical reason I’m looking for a Heroku alternative is that I’m using its Heroku Postgres service. The comment system of this blog is powered by thanks to Randy (the creator), self hosted by Vercel (compute) and Heroku Postgres (storage) with a simple comment form widget (iframe) at the bottom of this page. Since it's mostly a quiet blog, the free-tier plan of both services is more than enough for comments.

Migration Guide

Smart move, isn't it?

Migration Steps

Breaking down into 2 parts, 1) Migrating the data to Fly Postgres 2) Exposing to external connections (i.e. DB_URL for above Vercel app to connect).

Migrating the data to Fly Postgres

  1. Provision database app
    1. fly pg create -n "cusdis-db"
      fly secrets set -a cusdis-db DATABASE_URL=postgres://postgres:<password>@cusdis-db.internal:5432
  1. Data transfer
    1. fly secrets set -a cusdis-db HEROKU_DATABASE_URL=$(heroku config:get -a cusdis2 DATABASE_URL)
      fly ssh console -a cusdis-db createdb --maintenance-db $DATABASE_URL cusdis pg_dump -Fc --no-acl --no-owner -d $HEROKU_DATABASE_URL | pg_restore --verbose --clean --no-acl --no-owner -d $DATABASE_URL/cusdis
      fly secrets unset HEROKU_DATABASE_URL DATABASE_URL -a cusdis-db
  1. Verify
    1. fly pg connect -a cusdis-db -d cusdis

Exposing to external connections

  1. IP allocation
    1. fly ips allocate-v4 -a cusdis-db
  1. Expose external port
    1. Pull down fly.toml configuration file
      fly config save --app cusdis-db
      Update above configuration file
      [[services]] internal_port = 5432 # Postgres instance protocol = "tcp" [[services.ports]] handlers = [] port = 10000
  1. Deploy and verify changes
    1. fly deploy -a cusdis-db --image flyio/postgres:14 fly info -a cusdis-db

Wrap up

By combining IP and public port above, we should be able to get the database url, something that looks like postgres://postgres:<pasword>@<host IPv4 address>:10000/cusdis . Just replace the old url with this new one and test with a few comments, then we should be 🥂.
  • Rename. i.e. replace cusdis-db appeared in above commands with your own app-db name