Trying out NestJS part 1: Setting up a dev environment for your React / NestJS applications that rocks
Tags: react, docker, nestjs
Published: 2021-01-03 11:15:11

*This article was originally published on my [personal blog](https://arnaudcortisse.com/blog).*

## Introduction

In the context of my current job, I wanted to evaluate the various existing backend frameworks based on NodeJS. Why is that? The only Node.js backend framework I had ever used so far was express, which is an awesome light-weight framework, but that doesn't have any opinion whatsover on how you should structure your app.

During my investigation, I came across NestJS several times. The most appealing thing to me was its thorough documentation and its large ecosystem. I was especially interested in the OpenAPI integration, which I knew could greatly improve the frontend development experience when coupled with a code generator.
In the end, I decided to create a small POC to see whether it would be a fit.

## Specifications of the project

### Functional requirements

The POC is going to be a minimal, hideous "TODO list" app (styling is not in the scope of this endeavor).
In this POC, I'll be able to:

- Add tasks,
- Remove tasks,
- List all tasks

### Technical requirements

- Use Typescript everywhere.
- NestJS for the backend.
- React for the frontend.
- Tasks are saved in a Postgres DB.
- Redis is used for caching responses.
- API endpoints are documented using OpenAPI.
- API endpoints' parameters are validated in the backend.
- Frontend code related to the API endpoints is auto-generated.
- The development environment is set up in docker.
- Monorepo containing both the backend and the frontend.

## Building the project

The source code for this part of the project is available here: https://github.com/arnaud-cortisse/trying-out-nestjs-part-1.

### Setting up Docker dev environment

Since I took [Docker and Kubernetes: The Complete Guide](https://www.udemy.com/course/docker-and-kubernetes-the-complete-guide/) and [Microservices with Node JS and React](https://www.udemy.com/course/microservices-with-node-js-and-react/) courses, I've been a huge fan of setting up my dev environment inside docker instances instead of setting it up directly on my machine. I love the fact that I can have everything up and running with a single command, without having to worry about dependency conflicts (is my current version of NPM compatible with that project?, etc.).

#### A few commands to execute

- Install the Nest CLI: `npm i -g @nestjs/cli` (you might need to prefix it with `sudo`)
- Create an empty folder: `mkdir todo-list-app`
- Go inside the folder: `cd todo-list-app`
- Init npm package: `npm init -y`
- Init git, if you want to save your work: `git init`
- Create frontend folder: `mkdir -p packages/react-app`
- Create backend folder: `mkdir -p packages/nestjs`
- Create the React app: `npx create-react-app packages/react-app --template typescript`
- Create the NestJS app: `nest new packages/nestjs`
- Delete the .git folder automatically created by NestJS: `rm -rf packages/nestjs/.git`
- Create frontend env variables file: `touch packages/react-app/.env.dev`
- Create backend env variables file: `touch packages/nestjs/.env.dev`
- Create frontend Dockerfile for dev environment: `touch packages/react-app/Dockerfile.dev`
- Create backend Dockerfile for dev environment: `touch packages/nestjs/Dockerfile.dev`
- Create docker-compose file for dev environment: `touch docker-compose.yml`
- Create frontend .dockerignore file: `touch packages/react-app/.dockerignore`
- Create backend .dockerignore file: `touch packages/nestjs/.dockerignore`

#### A few files to fill / change

##### packages/react-app/Dockerfile.dev

```
FROM node:alpine
WORKDIR /app

COPY package.json .
RUN npm install --legacy-peer-deps
COPY . .

CMD ["npm", "run", "start"]
```

`--legacy-peer-deps` is just a temporary fix for https://github.com/facebook/create-react-app/issues/9515.

##### packages/nestjs/Dockerfile.dev

```
FROM node:alpine

WORKDIR /app
RUN npm install -g @nestjs/cli
COPY package.json .
RUN npm install
COPY . .

CMD ["npm", "run", "start:dev"]
```

Nothing crazy here, but we just make sure we install the NestJS CLI globally before doing anything else.

##### packages/react-app/.env.dev

```
REACT_APP_BACKEND_SCHEMA=http
REACT_APP_BACKEND_HOSTNAME=localhost
REACT_APP_BACKEND_PORT=3001
CHOKIDAR_USEPOLLING=true
```

`CHOKIDAR_USEPOLLING` is required when developing inside a docker container and using create-react-app (https://github.com/facebook/create-react-app/issues/1049#issuecomment-261731734).
The other variables are defined so that we can communicate with the NestJS API.

##### packages/nestjs/.env.dev

```
NEST_PORT=3001
PGHOST=postgres
PGPORT=5432
PGUSER=postgres
PGPASSWORD=example
PGDATABASE=postgres
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=password
REDIS_TTL=10
```

We define the port on which NestJS will run as well as the Postgres and Redis configs.

##### packages/react-app/.dockerignore

```
node_modules
```

We don't want the local `node_modules` folder to be copied over the instance.

##### packages/nestjs/.dockerignore

```
node_modules
```

##### docker-compose.yml

```
version: "3.5"

services:
  nestjs:
    build:
      context: ./packages/nestjs
      dockerfile: Dockerfile.dev
    env_file:
     - ./packages/nestjs/.env.dev
    ports:
      - 3001:3001
    volumes:
      - ./packages/nestjs/:/app
      - /app/node_modules

  react_app:
    build:
      context: ./packages/react-app
      dockerfile: Dockerfile.dev
    env_file:
     - ./packages/react-app/.env.dev
    ports:
      - 3000:3000
    volumes:
      - ./packages/react-app/:/app
      - /app/node_modules

  postgres:
    image: postgres:13.1
    environment:
      POSTGRES_PASSWORD: example
    ports:
     - 5432:5432

  redis:
    image: redis:6.2-rc1
    environment:
      REDIS_PASSWORD: password

  redis_commander:
    image: rediscommander/redis-commander:latest
    restart: always
    environment:
      - REDIS_HOSTS=local:redis:6379
    ports:
      - 8081:8081
    depends_on:
      - redis
```

- `nestjs` is our backend.
- `react_app` is our frontend.
- `postgres` is going to be used to store the tasks.
- `redis` is going to be used by NestJS to cache responses.
- `redis_commander` is just a tool that allows us to examine the Redis DB quickly.
- `volumes` under react_app and nestjs is key to get auto-reload whenever you modify files inside your editor. The only annoying thing with this setup is that you'll need to rebuild your docker images whenever you add a new dependency inside your node_modules (see https://github.com/BretFisher/node-docker-good-defaults for fixes). 

##### packages/nestjs/src/main.ts

```
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.NEST_PORT);
}
bootstrap();

```

Modify the port the app is listening to using the process.env.NEST_POST environment variable (defined in packages/nestjs/.env.dev).

### Test current setup

You should now be able to start your dev environment typing `docker-compose up` in the root directory.

You can then go to the following addresses:

- `localhost:3000` --> React app.
- `localhost:3001` --> NestJS app.
- `localhost:8081` --> Redis Commander (which should be connected to your Redis instance).

### Final words

With the current state, I've a working dev environment inside dev containers. All I have to do to get started is `docker-compose up` (sometimes, I have to do a `docker-compose up --build`, depending on whether or not new npm packages have been installed).
Whenever I update any `.ts` files in my code editor, the apps are reloaded accordingly, making it a very pleasant dev experience for the task at hand: asserting whether or not NestJS is going to be a good fit for me by developing a POC.

[Part 2 is available here](/blog/trying-out-nestjs-part-2/).