DEV Community

Navaneeth Pk
Navaneeth Pk

Posted on

Deploying a NestJS application with PostgreSQL database and react frontend on Heroku

Recently, we ported the 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

{
  "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"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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.

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.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 }
Enter fullscreen mode Exit fullscreen mode

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).

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
Enter fullscreen mode Exit fullscreen mode

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

npm install --save @nestjs/serve-static
Enter fullscreen mode Exit fullscreen mode

2) Modify AppModule

Add this to the imports.

ServeStaticModule.forRoot({
    rootPath: join(__dirname, '../../../', 'frontend/build'),
}),
Enter fullscreen mode Exit fullscreen mode

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.

app.setGlobalPrefix('api');
Enter fullscreen mode Exit fullscreen mode

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.

"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 "
}
Enter fullscreen mode Exit fullscreen mode

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/

Discussion (0)