Deploying a NestJS application with PostgreSQL database and react frontend on Heroku
Tags: nestjs, react, heroku, typeorm
Published: 2021-07-30 03:43:15

Recently, we ported the [ToolJet](https://github.com/ToolJet/ToolJet) server from Ruby on Rails to NestJS, ToolJet can be deployed to Heroku using the one-click deployment feature of Heroku. ToolJet server is built using Nest.js with TypeORM as the ORM and PostgreSQL as the database. This article will explain how to deploy a NestJS API application on Heroku using the one-click deployment feature of Heroku.

Many of our users deploy the frontend and backend separately, the backend might be deployed on Heroku/K8S/EC2 while the frontend is served from Firebase/Netlify/etc. The first part of this guide explains how to deploy a NestJS API to Heroku and the last part explains how to deploy the frontend too.

###1) Create app.json file in the root directory of your repository

```json
{
  "name": "ToolJet",
  "description": "ToolJet is an open-source low-code framework to build and deploy internal tools.",
  "website": "https://tooljet.io/",
  "repository": "https://github.com/tooljet/tooljet",
  "logo": "https://app.tooljet.io/assets/images/logo.svg",
  "success_url": "/",
  "scripts":{
    "predeploy": "npm install && npm run build"
  },
  "env": {
    "NODE_ENV": {
      "description": "Environment [production/development]",
      "value": "production"
    }
  },
  "formation": {
    "web": {
      "quantity": 1
    }
  },
  "image": "heroku/nodejs",
  "addons": ["heroku-postgresql"],
  "buildpacks": [
    {
      "url": "heroku/nodejs"
    }
  ]
}
```

Environment variables, add-ons, buildpacks and other information about the app needs to be added to the app.json file. More details about the app.json manifest can be found [here](https://devcenter.heroku.com/articles/app-json-schema#stack).

Using the predeploy hook, we are installing the npm packages required for the application and then build the application. `npm run build` runs the nest build command. More details about nest build can be found [here](https://docs.nestjs.com/cli/usages#nest-build).We have also added `heroku-postgresql` to the addons so that a Postgres database will be provisioned by Heroku. 

###2) Listen to the port assigned by Heroku
Heroku dynamically assigns a port for your app. We need to make sure that the application is listening to requests on the port assigned by Heroku.  Modify the `main.ts` file to listen to the port assigned by Heroku and fallback to 3000. We also need to set 0.0.0.0 as the binding address.

```app.listen(parseInt(process.env.PORT, '0.0.0.0') || 3000);```

Note: you will come across the following error if the application is listening on a different port. Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch 

###3) Configuring TypeORM to use Postgres database provisioned by Heroku

Add the following options to your `ormconfig(.json/.ts/.js)` file. 

```
url: process.env.DATABASE_URL,
ssl: { rejectUnauthorized: false }
```

`DATABASE_URL` config variable is added to your app's environment if a Postgres resource is provisioned for your app. Without setting the `rejectUnauthorizedoption` as false, Error: self signed certificate will be thrown by the application (the reason is explained [here](https://stackoverflow.com/questions/61097695/self-signed-certificate-error-during-query-the-heroku-hosted-postgres-database)). 

###4) Procfile

Add `web: npm run start:prod` as a new line to Procfile. We are assuming that the start:prod script is defined in package.json as `NODE_ENV=production node dist/src/main`. TypeORM migrations can be run after every release. 

Add `release: npm run typeorm migration:run` as a new line to your Procfile. The Procfile will now look like this:

```
web: npm run start:prod
release: npm run typeorm migration:run
```

###5) Deploy!

You can visit https://heroku.com/deploy?template=https://github.com/your-organization/your-repository/tree/your-branch to deploy the application using the one-click deployment feature of Heroku.

If you want to deploy just NestJS API on Heroku, you can stop reading this guide. If you want to deploy the frontend too to Heroku, please continue. 

In the following steps, we will explain how to make NestJS serve a React single page application. We are assuming that the React application lives under the frontend directory.

###1) Install serve-static NestJS plugin 

```bash
npm install --save @nestjs/serve-static
```

###2) Modify AppModule 

Add this to the imports.

```typescript
ServeStaticModule.forRoot({
	rootPath: join(__dirname, '../../../', 'frontend/build'),
}),
```

### 3) Routing 

Now the NestJS will serve  index.html in the build directory of the frontend. This can be a problem when there are similar routes on the frontend and backend. For example, if the frontend application's path for users page is /users and the path to fetch users from the backend is also the same, NestJS will not serve the static files for that path. To solve this issue, let's add a prefix to the backend endpoints.

```javascript
app.setGlobalPrefix('api');
```

This line needs to be added to `main.ts` to make sure the path for all API requests starts with api. For example: http://localhost/api/users.

###4) Build the frontend while deploying to Heroku

We need to build the frontend for production to generate the build folder.

```json
"scripts": {
    "build": "npm --prefix frontend install && NODE_ENV=production npm --prefix frontend run build && npm --prefix server install && NODE_ENV=production npm --prefix server run build",
    "deploy": "cp -a frontend/build/. public/",
    "heroku-postbuild": "npm run build && npm run deploy",
    "heroku-prebuild": "npm --prefix frontend install && npm --prefix server install "
}
```

Add this to the package.json on the root directory of the repository.

###5) Deploy!

You can visit https://heroku.com/deploy?template=https://github.com/your-organization/your-repository/tree/your-branch to deploy the application using the one-click deployment feature of Heroku.
We would love you to check out ToolJet on GitHub: https://github.com/ToolJet/ToolJet/