Dockerizing a NestJS app and persisting data
Tags: docker, nestjs, postgres, prisma
Published: 2023-10-29 15:33:02

It has been a while since our last post, and we have successfully achieved our goal of reaching 20k this year. I am extremely glad, and this achievement motivates me to do a lot more. Hopefully, this year, Inshallah, we will reach 50k. Anyway, let's begin. Our topic revolves around **Dockerizing a NestJS app and persisting data**.

In this scenario, I'll be utilizing PostgreSQL and Prisma. **I'll assume you're already familiar** with creating a NestJS application and integrating Prisma. If not, please leave a comment below, and I'll create a dedicated post on the process.

**1- Setup your nestjs app**

**2- Add dockerFile:**
Create it as a regular file within your project, not within the 'src' directory but at the same level as 'package.json'. Simply name it **Dockerfile**
 i will explain it line by line :
      ▶ builder stage:
     ❶ : FROM node:latest AS builder : 
            - This line sets the starting point for building our Docker image by using the most recent version of Node.js from Docker Hub.
   
     ❷ : WORKDIR /app :
            -  Sets the working directory inside the Docker container to /app

    ❸ : COPY package*.json ./
        COPY prisma ./prisma/ : 
           - COPY package*.json ./ and COPY prisma ./prisma/: Copies the package.json and package-lock.json files as well as the prisma directory from the host machine to the /app directory in the container

   ❹ : RUN npm install --force : 
        -  Executes the npm install command to install the project dependencies defined in package.json.
 
  ❺ : COPY . . :
        -  Copies all files from the current directory of the host machine to the /app directory in the container

 ❻ : RUN npm run build :
      - Executes the command to build the project

    ▶ Final stage : This is the final image that will be created. It's based on the Node.js image without any specific name/alias.

**copies only the essential artifacts needed to run the application from the "builder" stage (node_modules, package*.json, dist directory). This selective copying helps keep the final image small and efficient.**

   ❶ : FROM node:latest

   ❷ : WORKDIR /app

  ❸ : 
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/dist ./dist
      - Copies specific directories from the 'builder' stage to the respective directories in the new stage

         ❹ : EXPOSE 3000 : 
       -  Informs Docker that the container listens on port 3000 at runtime

        ❺ : CMD [ "npm", "run", "start:prod" ]:
      - Specifies the default command to be executed when the container starts

the final result : 

```
FROM node:latest AS builder

WORKDIR /app

COPY package*.json ./
COPY prisma ./prisma/

RUN npm install --force

COPY . .

RUN npm run build

FROM node:latest

WORKDIR /app

COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD [ "npm", "run", "start:prod" ]
```

**The next crucial step** is to generate a 'docker-compose.yml' file at the same level as the 'Dockerfile'.
   
  ❶ : version: '1.1'  # Specifies the version of the Compose file format being used.
  ❷ : services: will contain our services :
      

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ni6e95nml1i6pq6hf35z.png)

----
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5nh0mb2iq7zkpgctq9je.png)

----

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0lr01aqdxuwbbicdov4o.png)

the final result will be like this : 

```
version: '3.8'
services:
  prisma-migrate:
    container_name: prisma-migrate
    build:
      context: prisma
      dockerfile: Dockerfile
    environment:
      DATABASE_URL: ${DATABASE_URL}
    depends_on:
      - postgres

  postgres:
    image: postgres:13
    container_name: postgres
    restart: always
    ports:
      - '5432:5432'
    env_file:
      - .env
    volumes:
      - postgres:/var/lib/postgresql/data

  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:
      - postgres

volumes:
  postgres:
    name: nest-db

```

and now just run  : **docker compose up -d **


Hopefully, this brings value and aids you,Feel free to leave a comment if this was helpful or if you have any questions. I'm here and ready to provide further assistance.for more tips you can follow me here [linkedin](https://www.linkedin.com/in/tarek-chafroud-6725711bb/).