Deploying Nx workspace based Angular and NestJS apps to Heroku

In previous articles, I've shown you how to create an Nx Workspace with Angular and NestJS applications in it. After the applications are ready, we need to host them somewhere. Heroku is one of the services that lets us deploy applications easily. In this article, I'll demonstrate how to deploy the Angular and NestJS applications that are developed using an Nx monorepo. You can find the example code with the aforementioned applications in my GitHub repository. To follow this article, please fork this repo, clone it locally and checkout nxDeployHeroku_entryPoint.

git clone [email protected]:<your_username>/nx-photos.git

# Or using Https
git clone https://github.com/<your_username>/nx-photos.git

cd nx-photos

git checkout nxDeployHeroku_entryPoint

Install Heroku CLI

To follow this article, you need to have the Heroku CLI installed. Please follow the official installation instruction on the Heroku documentation page here.
After you install the CLI, type the following command to log in to Heroku:

heroku login

Deploying NestJS app

We're going to start with deploying the NestJS application. The first thing we need to do is creating a Heroku application. Because you need to come up with a unique application name in all the examples, I'll be using ktrz- prefix for the app names. Please replace it with your own prefix so that the application names don't collide with each other.

To create a Heroku application we can use the following command:

heroku create -a ktrz-nx-photos-api

Now we need to configure the application to use Node for building the application. This is what buildpacks are for. To add a buildpack, the heroku buildpacks:add command can be used:

heroku buildpacks:add -a ktrz-nx-photos-api heroku/nodejs

Heroku uses a Procfile file to specify the commands that are executed on application startup. The default configuration allows for only one Procfile and it has to be in the repository root. For it to work with the monorepo with multiple applications, we need a way to configure multiple Procfiles in the repository. For this purpose, a multi-procfile buildpack can be used. We can add it using a similar command to the previous one:

heroku buildpacks:add -a ktrz-nx-photos-api heroku-community/multi-procfile

Now we can create a Procfile and place it in the directory that makes sense for the monorepo. Let's create the following file:

web: node dist/apps/photo/api/main.js

apps/photo/api/Procfile

To let the buildpack know about the location of the Procfile, we need to set PROCFILE env variable for the Heroku application. We can do it using the following command:

heroku config:set -a ktrz-nx-photos-api PROCFILE=apps/photo/api/Procfile

By default, Heroku uses the build script from the package.json file to build the application. We need a more customizable way of building an application so we can configure which application in a monorepo to build. By defining a heroku-postbuild script, we tell Heroku to not use a default build one and use our custom script instead. Let's create the following script:

scripts: {
  "heroku-postbuild": "nx build $PROJECT_NAME --prod"
}

package.json

As you can see, the PROJECT_NAME env variable is used to determine which application to build. It needs to be configured on the Heroku environment:

heroku config:set -a ktrz-nx-photos-api PROJECT_NAME=photo-api

What is left to do is push the changes to a branch and configure Heroku app to use the repository as a source for deployment:

git checkout -b nx-photo-deploy

git push -u origin photo-api-deploy

To configure the Heroku app, go to the dashboard and choose the application that you've created before:

Next, navigate to the Deploy tab, choose the GitHub method, search for your repository, and click Connect:

Finally, on the bottom, you can choose to deploy manually from the branch that you've created a moment ago:

  • in package.json add script:
scripts: {
  "heroku-postbuild": "nx build $PROJECT_NAME --prod"
}

package.json

heroku create -a ktrz-nx-photos-api
heroku config:set -a ktrz-nx-photos-api PROJECT_NAME=photo-api

heroku buildpacks:add -a ktrz-nx-photos-api heroku/nodejs
heroku buildpacks:add -a ktrz-nx-photos-api heroku-community/multi-procfile

# create `apps/photo/api/Procfile` file
heroku config:set -a ktrz-nx-photos-api PROCFILE=apps/photo/api/Procfile

To learn more about heroku-buildpack-nodejs and heroku-buildpack-multi-procfile configuration, please visit the official documentation:

Deploying Angular app

Deploying an Angular app has a lot of similar steps.

# create another Heroku app
heroku create -a ktrz-nx-photos-fe

# add same buildpacks
heroku buildpacks:add -a ktrz-nx-photos-fe heroku/nodejs
heroku buildpacks:add -a ktrz-nx-photos-fe heroku-community/multi-procfile

# configure Procfile
heroku config:set -a ktrz-nx-photos-fe PROCFILE=apps/photo/fe/Procfile

# set PROJECT_NAME env variable
heroku config:set -a ktrz-nx-photos-fe PROJECT_NAME=photo-fe

The Angular application can be served as just static files with routing configured to always point to the root index.html and let Angular handle the rest. We can use another buildpack to accomplish that.

heroku buildpacks:add -a ktrz-nx-photos-fe heroku-community/static

heroku-buildpack-static is configured via static.json file. We can do a basic configuration like so:

{
  "root": "dist/apps/photo/fe/",
  "routes": {
    "/**/*.html": "index.html"
  }
}

static.json

The example Angular application is configured to use /api proxy for the backend. This also can be configured within static.json file:

{
  "proxies": {
    "/api/": {
      "origin": "https://ktrz-nx-photos-api.herokuapp.com/api/"
    }
  }
}

static.json

The last thing to do is configure Heroku to use the static buildpack via the Procfile:

web: bin/boot

apps/photo/fe/Procfile

To learn more about heroku-buildpack-static configuration, please visit the oficial documentation here.

Let's commit the changes and configure the second app to use the same GitHub repository:

  • Go to dashboard and choose the frontend application that you've created before.
  • Next, navigate to the Deploy tab, choose GitHub method, search for your repository, and click Connect.
  • Finally, on the bottom you can choose to deploy manually from the branch that you've pushed to a moment ago.

After all those steps, you can navigate to your deployed app:

Summary

If you want to see the result code, you can find it on my GitHub repository.

In case you have any questions, you can always tweet or DM me @ktrz. I'm always happy to help!

This Dot Labs is a modern web consultancy focused on helping companies realize their digital transformation efforts. For expert architectural guidance, training, or consulting in React, Angular, Vue, Web Components, GraphQL, Node, Bazel, or Polymer, visit thisdotlabs.com.

This Dot Media is focused on creating an inclusive and educational web for all. We keep you up to date with advancements in the modern web through events, podcasts, and free content. To learn, visit thisdot.co.

32