Deploy to Multiple Heroku Instances from a Monorepo

I use Heroku quite often, especially when I have a lot of momentum and excitement starting a new idea/project and don’t want to lose it while setting up IAM permissions on AWS.

info
If you are not familiar with Heroku, it an abstraction on top of AWS that manages your server deployments with Git. You just add a new remote that points to Heroku and when you want to deploy, push to that remote.

When a repo has more than one Heroku app

Recently, a monolith Node.js project that was hosted on Heroku, needed to be split into two.

The new structure looks like this:

project-repo
└───apiOne
│   │   index.js
│   │   package.json
│
└───apiTwo
    │   index.js
    │   package.json

With this structure, I had a single repository that would need to publish to multiple Heroku instances and the individual Node.js apps are kept in subdirectories, so I’ll need to publish just that subdirectory to Heroku.

Add remotes to subdirectories

We are going to use the Heroku CLI to add remotes that point to different Heroku instances.

If you don’t have any instances created, use heroku create and a remote called heroku will be automatically created that points to a newly created Heroku instance.

If you have already created your Heroku instance, then you can use heroku git:remote -a my-heroku-app-name.

In either case, a remote called heroku will be created in your local repository. This is fine if you are just deploying to a single Heroku instance, but we need multiple remotes pointing to different Heroku instances. To get around this, we just need to rename the heroku remote to something else before we add the second remote.

cd project-repo

# add the first remote
heroku git:remote -a apiOne-name
#set git remote heroku to https://git.heroku.com/apiOne-name.git

#next, rename the remote
git remote rename heroku heroku-apiOne

#now we can add second remote

heroku git:remote -a apiTwo-name
#set git remote heroku to https://git.heroku.com/apiTwo-name.git

#rename the remote
git remote rename heroku heroku-apiTwo

Now, we will have two remotes that point to two Heroku instances.

Deploy scripts

Next, we need a way to push just the subdirectory to the correct remote.

Since we are building Node.js apps, we can use a npm script to help us publish to our Heroku remotes.

Inside ./project-repo/apiOne/package.json , look for the scripts property:

...
"scripts": {
    "start": "node index.js"
  },
...

and add the following custom script:

...
"scripts": {
    "start": "node index.js",
    "publish-apiOne": "cd ../ && git subtree push --prefix apiOne heroku-apiOne master"
  },
...

This script:

  1. cd ../ Goes to the project-repo root, where git is configured.
  2. git subtree push --prefix apiOne Uses the git subtree command to push just the apiOne subdirectory.
  3. heroku-apiOne master Heroku remote name and its’ branch name that we want to push to.

Now for ./project-repo/apiTwo/package.json,

...
"scripts": {
    "start": "node app.js",
    "publish-apiTwo": "cd ../ && git subtree push --prefix apiTwo heroku-apiTwo master"
  },
...

Run

cd project-repo/apiOne
npm run publish-apiOne

That’s it!