Deploying Angular and NestJS apps to Heroku in an Nx workspace
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 git@github.com:<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 clickConnect
. - 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!