Copying an existing database from heroku to a review app

Working with Heroku makes life generally very easy. You can setup deploys on every commit to a specific branch and have review apps created with each pull request in Github.

One thing however that heroku unfortunately does not make very easy is duplicating databases between an existing app and a PR app.

Heroku recommends to use seeds instead of copying a database. This would generally be the right way to go, but sometimes there's reasons where you need a copy of an existing database

In order to copy a database from an existing heroku app to a new review app we really need to specify one command, but in order to run that command we'll need to setup the right configuration.

Here's the command we'll need to run in our postdeploy, as that only runs the first time and not everytime after a commit:

heroku pg:copy [source-app]::[DATABASE-NAME] [TARGET-DATABASE-NAME] -a $HEROKU_APP_NAME --confirm $HEROKU_APP_NAME

This seems pretty easy, but unfortunately won't run. This is what we'll need to do to get it to work:

  • Add a buildpack to run heroku commands in a dyno
  • Setup an api key in the review app configuration environment variables to authenticate the heroku request

Add the heroku cli buildpack and the postdeploy step

If you haven't add one yet, add app.json and make sure there is a review environment like below included. In this example the source app is called develop-app and both databases are called DATABASE in both the develop and review app.

"environments": {
    "review": {
      ...
      "scripts": {
        "postdeploy": "heroku pg:copy develop-app::DATABASE DATABASE -a $HEROKU_APP_NAME --confirm $HEROKU_APP_NAME"
      },
      "buildpacks": [
          {
            "url": "https://github.com/heroku/heroku-buildpack-cli"
          }
      ]
   }
   ...
}

HEROKU_APP_NAME is an env var automatically set by heroku for each app. In our case it is the review app where we want to override the database.

For every new review app that is created it will add the heroku cli buildpack allowing you to run heroku commands on a dyno.

Authentication in the Dyno

In order to run any heroku command in the dyno you either need to be logged in or set an api key in other to authenticate. If this is going to be part of an automatic deployment we dont want to login each time. So instead we'll set an api key.

On a local terminal (assuming you have already logged into the CLI app with your username/password) run:

heroku authorizations:create --short

This will create a long-lived token you can use to set HEROKU_API_KEY in the review app environment variables that looks like a guid id.

With HEROKU_API_KEY set, the postdeploy script can now run as an automated post deploy step.