Step-by-Step Guide: Setting Up a NestJS Application with Docker and PostgreSQL
Tags: webdev, javascript, node, backend
Published: 2023-04-10 13:17:15

NestJS, PostgreSQL, and Docker are three powerful tools that can help you build robust web applications quickly and easily. NestJS is a modern, progressive Node.js framework that allows you to build server-side applications using TypeScript. PostgreSQL is a powerful open-source database management system that provides reliable data storage and retrieval. Docker is a containerization platform that simplifies the deployment and management of applications. 

These three tools provide a powerful toolkit for building scalable and efficient web applications. This article will give a beginner-friendly guide to using NestJS, PostgreSQL, and Docker to build a web application. 

## Repository
{% embed https://github.com/folucode/nest-docker-postgres-tut %}

## Prerequisite
- Basic understanding of TypeScript, PostgreSQL, and RESTful APIs
- Docker Desktop installed on your computer (run the `docker -v` command to verify the installation); if not, install it from [here](https://www.docker.com/products/docker-desktop/)

## Setting Up a NestJS Application

We need [node](https://nodejs.org/en/) and its package manager [npm](https://www.npmjs.com/) to initialize a new project. 

To install Node, we go to the [Nodejs website](https://nodejs.org/en/) and follow the instructions. We verify Node.js’ installation using the terminal command below: 
 

    node -v
    v18.15.0 //node version installed

 
The result shows the version of Node.js we installed on our computer.

Next we’ll install NestJS globally and initialise a new project by running the command below in our terminal:


    $ npm i -g @nestjs/cli
    
    $ nest new nest-docker-postgres

Make sure to choose `npm` as the package manager from the prompt. 

Start the development server using the command below and visit http://localhost:3000/ to see the application running:


    $ npm run start:dev

## Containerizing the Application

To containerize our NestJS application, we first create a file named `Dockerfile` in the root of our project and then a `docker-compose.yml` file also in the root of our project.

The `Dockerfile` sets up a container for running the application. It installs the necessary dependencies, copies the application code into the container, builds the application, and starts the server using the production build.

The `docker-compose` file sets up a multi-container environment. In it, we would run the NestJS app with PostgreSQL and pgAdmin.

*Dockerfile*

    FROM node:18
    
    WORKDIR /app
    
    COPY package*.json ./
    
    RUN npm install
    
    COPY . .
    
    RUN npm run build
    
    CMD [ "npm", "run", "start:dev" ]

Here's what each command in this file does:


1. **`FROM node:18`**: Specifies the base image for the Docker container. We use the official Node.js `18.x` image as the base in this case.


2. **`WORKDIR /app`**: Sets the working directory inside the container to `/app`. This is where the application code will be copied and where the container will run from.


3. **`COPY package*.json ./`**: Copies the `package.json` and `package-lock.json` files from the current directory on the host machine to the `/app` directory in the container. The `*` in `package*.json` allows us to copy both files at once.


4. **`RUN npm install`**: Installs the application dependencies in the container. This step uses the `npm install` command to install the dependencies listed in `package.json`.


5. **`COPY . .`**: Copies the application code from the host machine to the `/app` directory in the container.


6. **`RUN npm run build`**: The `npm run build` command is used to build the application in the container. This command will typically create a `dist` folder with the production build of the application.


7. **`CMD ["npm", "run", "start:dev"]`**: Specifies the command to run when the container starts. In this case, we're running the `npm run start:dev` command, which will start the server in development mode. This command watches for changes in the code and automatically rebuilds the container when changes are detected. This allows for faster development cycles, as changes to the code can be quickly tested in the container without manual rebuilding or restarting.

*docker-compose.yml*

    version: '3.5'
    
    services:
      db:
        image: postgres
        restart: always
        environment:
          - POSTGRES_PASSWORD=postgres
        container_name: postgres
        volumes:
          - ./pgdata:/var/lib/postgresql/data
        ports:
          - '5432:5432'
    
      app:
        build:
          context: .
          dockerfile: Dockerfile
        container_name: nest-docker-postgres
        environment:
          - PORT=${PORT}
        ports:
          - '3000:3000'
        depends_on:
          - db
        volumes:
          - ./src:/app/src
    
      pgadmin:
        image: dpage/pgadmin4
        restart: always
        container_name: nest-pgadmin4
        environment:
          - PGADMIN_DEFAULT_EMAIL=admin@admin.com
          - PGADMIN_DEFAULT_PASSWORD=pgadmin4
        ports:
          - '5050:80'
        depends_on:
          - db
    

In this file:


- **`version`**: This field at the beginning of a Docker Compose file specifies the version of the Compose file format we’re using.


- **`db`**: This service sets up a PostgreSQL database using the official `postgres` image from Docker Hub. It sets the password for the `postgres` user to `postgres`, creates a named volume `pgdata` for storing the database data, and maps the container port `5432` to the host port `5432`. The `restart: always` option ensures that the container will automatically restart if it crashes or is stopped.


- **`app`**: This service builds a Docker image for the NestJS app using the `Dockerfile` in the current directory. It sets the container name to `nest-docker-postgres`, sets the environment variable `PORT` to the value of the host `PORT` environment variable, maps the container port `3000` to the host port `3000`, and mounts the `src` directory on the host to the `/app/src` directory in the container. The `depends_on` option specifies that this service depends on the `db` service, meaning that the `db` container will be started before the `app` container.


- **`pgadmin`**: This service sets up pgAdmin, a web-based PostgreSQL administration tool, using the `dpage/pgadmin4` image from Docker Hub. It sets the container name to `nest-pgadmin4`, sets the default email and password for the pgAdmin login, maps the container port `80` to the host port `5050`, and specifies that this service depends on the `db` service.

We also need to add a new file called `.dockerignore`. It specifies files and directories that `.dockerignore` should exclude from a Docker build context.

*.dockerignore*

    Dockerfile
    .dockerignore
    node_modules
    npm-debug.log
    dist
    


### Building the containers

The next thing we need to do is build to run our app in Docker - building the containers. Run the command below to containerize the application:


    $ docker compose up

The command looks for the services specified in the **`docker-compose.yml`** file and creates containers for them. If the images required by those services are unavailable locally, Docker will pull them from Docker Hub or any other configured registry. If the images are already available locally, Docker will use them instead of pulling them again.

Once the containers are up and running, we can access the NestJS application by visiting [**http://localhost:3000**](http://localhost:3000) in our web browser and pgAdmin by visiting [**http://localhost:5050**](http://localhost:5050) in our web browser.

Login to pgAdmin by using the email and password we specified earlier in the **`docker-compose.yml`** file, and then we will see this:

![pgAdmin dashboard](https://paper-attachments.dropboxusercontent.com/s_7415E88BE4457A77FEA4C2D866AF04C1AC88C287DCC302D45D2561FFF0E34A3D_1680976710611_Screenshot+2023-04-08+at+18.57.10.png)

## Setting up pgAdmin and PostgreSQL Server

To connect to the PostgreSQL server from PgAdmin, we need to create a server object in PgAdmin with the details of the PostgreSQL server. 

Here are the steps to create a server in PgAdmin:


1. Open PgAdmin in the web browser by visiting [http://localhost:5050](http://localhost:5050/) (assuming we're using the default configuration in the **`docker-compose.yml`** file).
2. Log in using your email and password in the **`docker-compose.yml`** file for the **`pgadmin`** service.
3. In the left-hand sidebar, click `Servers` to expand the `Servers` menu.
4. Right-click on `Servers` and select `Register` -> `Server`.
5. In the `General` tab of the `Create - Server` dialog, we can give the server a name of our choice.
6. In the `Connection` tab, fill in the following details:
    - Host name/address: **db**
    - Port: **5432**
    - Maintenance database: **postgres**
    - Username: **postgres**
    - Password: **postgres**
7. Click `Save` to save the server configuration.


> **Note:** Since the PostgreSQL server is running in a Docker container, the hostname/address would be the name of the Docker service for the database container as defined in the **`docker-compose.yml`**  file. By default, the name of the service becomes the hostname/address of the container within the Docker network.

We should now see the server we created in the left-hand sidebar of PgAdmin. We can expand the server to see the databases and other objects within it.

![PgAdmin dashboard](https://paper-attachments.dropboxusercontent.com/s_7415E88BE4457A77FEA4C2D866AF04C1AC88C287DCC302D45D2561FFF0E34A3D_1680977375412_Screenshot+2023-04-08+at+19.08.07.png)

## Connecting to PostgreSQL Server from NestJS

Nest provides the `@nestjs/typeorm` package for integrating with SQL and NoSQL databases. Install the packages using the command below:


    $ npm install --save @nestjs/typeorm typeorm pg

Next, in the `app.module.ts` file, add the following code in the `imports` array:

```javascript
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'db',
      port: 5432,
      username: 'postgres',
      password: 'postgres',
      database: 'postgres',
      entities: [],
      synchronize: true,
      autoLoadEntities: true,
    }),
```
We import the `TypeOrmModule` from the `@nestjs/typeorm` package.

We pass an `options` object to the `TypeOrmModule` to configure the PostgreSQL connection details. The `type` option specifies the database management system being used, PostgreSQL. The `host`, `port`, `username`, `password`, and `database` options provide the connection details for the PostgreSQL server.

We use the `entities` option to specify the entities that the application uses. Entities represent the data models in the application and can be used to query the database. We don't specify entities in this case because we dynamically load them by setting `autoLoadEntities` to `true`.

We set the `synchronize` option to `true`, which means that TypeORM will automatically generate database tables based on the entities. However, this option should be used with caution in production because it can cause data loss and conflicts.

To rebuild our app container because of the changes made, we execute the command below:


    $ docker compose up --build

And voila, our app is connected to the PostgreSQL server running in Docker. We can now start to create entities and build APIs on top of them.

## Conclusion

In conclusion, we have seen how to set up a NestJS application with Docker and PostgreSQL in a step-by-step guide. Using Docker and PostgreSQL in combination with NestJS can make your web application development faster and more efficient.

## Resources
- [NestJS Documentation](https://docs.nestjs.com/)
- [PostgreSQL Docker Image](https://hub.docker.com/_/postgres)
- [pgAdmin4 Docker Image](https://hub.docker.com/r/dpage/pgadmin4)