Deployment: Deploying a NestJS Application

Deploying a NestJS application to a cloud platform (e.g., AWS, Google Cloud, Azure) or a containerized environment (e.g., Docker, Kubernetes).


Dockerizing a NestJS Application

Introduction

This guide explains how to Dockerize a NestJS application using a Dockerfile and Docker Compose. Dockerizing your application offers several benefits including portability, consistency, and ease of deployment.

Prerequisites

  • Node.js and npm (or yarn) installed
  • NestJS CLI installed: npm i -g @nestjs/cli
  • Docker installed and running
  • Docker Compose installed

1. Creating a New NestJS Application

If you don't have an existing NestJS application, create a new one:

nest new my-nestjs-app
cd my-nestjs-app 

Follow the prompts to configure your project (e.g., select npm or yarn).

2. Creating a Dockerfile

Create a file named Dockerfile in the root of your NestJS project. This file contains instructions for building the Docker image:

 # Use an official Node.js runtime as a parent image
FROM node:18-alpine

# Set the working directory in the container
WORKDIR /app

# Copy package.json and package-lock.json (or yarn.lock) to the working directory
COPY package*.json ./

# Install dependencies
RUN npm install

# If using yarn, use the following command instead:
# RUN yarn install

# Copy the source code to the working directory
COPY . .

# Build the NestJS application
RUN npm run build

# Expose the port your application listens on (default is 3000)
EXPOSE 3000

# Define the command to run your application
CMD [ "node", "dist/main" ] 

Explanation of the Dockerfile:

  • FROM node:18-alpine: Specifies the base image. This uses a lightweight Alpine Linux-based image with Node.js version 18. Alpine is smaller, resulting in smaller image sizes.
  • WORKDIR /app: Sets the working directory inside the container to /app.
  • COPY package*.json ./: Copies the package.json and package-lock.json (or yarn.lock) files to the working directory. This allows Docker to cache the dependencies layer. Copying these separately speeds up builds when only the application code changes.
  • RUN npm install: Installs the application dependencies using npm. If you use yarn, replace with `RUN yarn install`.
  • COPY . .: Copies the entire source code to the working directory in the container.
  • RUN npm run build: Builds the NestJS application using the build script defined in your package.json (usually nest build).
  • EXPOSE 3000: Exposes port 3000, which your NestJS application will listen on. This is important for accessing the application from outside the container.
  • CMD [ "node", "dist/main" ]: Defines the command to start the application. This runs the compiled JavaScript file main.js located in the dist directory.

3. Creating a Docker Compose File

Create a file named docker-compose.yml in the root of your project. Docker Compose simplifies the management and orchestration of multi-container Docker applications.

 version: "3.8"
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      - db # If your app depends on a database

  db:  #Example section; remove or modify if your app doesn't need a DB.
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydb
    ports:
      - "5432:5432"
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data: 

Explanation of the Docker Compose file:

  • version: "3.8": Specifies the version of the Docker Compose file format.
  • services: Defines the services that make up your application.
  • app: Defines the NestJS application service.
    • build: .: Instructs Docker Compose to build the image using the Dockerfile in the current directory (.).
    • ports: - "3000:3000": Maps port 3000 on the host machine to port 3000 in the container. This allows you to access the application at localhost:3000.
    • environment: NODE_ENV: development: Sets the environment variable NODE_ENV to development. This can be useful for configuring your application differently in development and production.
    • volumes: - .:/app - /app/node_modules: Mounts the current directory (your project source code) into the /app directory in the container. This is important for development because it allows you to make changes to your code on the host machine and have them reflected immediately in the container (hot reloading). The second volume is crucial: it prevents the container's node_modules from being overwritten by your host's. This ensures that the `node_modules` within the container are always consistent with what was installed during the build.
    • depends_on: - db: Specifies that the app service depends on the db service. Docker Compose will start the db service before starting the app service. (Remove this if your app doesn't use a database)
  • db: (Example database service - remove or modify if not needed)
    • image: postgres:15-alpine: Uses the official Postgres 15 Alpine image.
    • environment: Sets environment variables for the database, such as the username, password, and database name.
    • ports: - "5432:5432": Maps port 5432 (Postgres default) on the host to the container.
    • volumes: - db_data:/var/lib/postgresql/data: Creates a named volume `db_data` to persist the database data.
  • volumes: Defines named volumes to persist data between container restarts. In this case, it defines the `db_data` volume for the database.

4. Building and Running the Application

Open your terminal and navigate to the root of your project. Run the following command to build and start the application:

docker-compose up --build 

The --build flag ensures that the Docker image is rebuilt if the Dockerfile has changed.

5. Accessing the Application

Once the application is running, you can access it in your browser at http://localhost:3000.

6. Stopping the Application

To stop the application, press Ctrl+C in the terminal where you ran the docker-compose up command. Then run:

docker-compose down 

This will stop and remove the containers created by Docker Compose.

7. Important Considerations

  • Environment Variables: Use environment variables for configuration settings like database credentials, API keys, and other sensitive information. These can be set directly in the docker-compose.yml file or loaded from a .env file.
  • Production Considerations: For production deployments, consider using a more robust image base, optimizing your Dockerfile, and using a dedicated orchestration platform like Kubernetes.
  • Volume Mounts: While volume mounts are great for development, consider using Docker volumes or bind mounts with caution in production.
  • Hot Reloading: NestJS supports hot reloading. Ensure your development environment is set up to take advantage of it. This often involves configuring webpack or similar tools.