Sling Academy
Home/Node.js/How to Dockerize a NestJS Application for Production

How to Dockerize a NestJS Application for Production

Last updated: December 31, 2023

Introduction

Deploying NestJS applications in a containerized environment ensures consistency across various development and production stages. This guide offers step-by-step instructions to dockerize your NestJS application for production using the latest syntax and best practices.

Prerequisites:

  • Basic understanding of Docker and its concepts.
  • Node.js and NestJS installed on your local machine.
  • A NestJS application ready for production.
  • Docker installed on your machine.

The Steps

Step 1: Create a Dockerfile

Creating a Dockerfile is the first step in dockerizing your NestJS application. It defines the environment and commands to build your Docker image.

# Start by specifying the base image
FROM node:latest

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
# A wildcard is used to ensure both package.json and package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

# Install all node modules
RUN npm install

# Bundle app source
COPY . .

# Build the project
RUN npm run build

# Your app binds to port 3000 so use the EXPOSE instruction
EXPOSE 3000

CMD [ "npm", "run", "start:prod" ]

Step 2: Optimize Your Dockerfile for Production

Optimize your Dockerfile to reduce the image size and improve the build time which is critical for production.

# Use a multi-stage build to reduce the image size
# Stage 1: Build the application
FROM node:latest as builder

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

RUN npm run build

# Stage 2: Setup the production environment
FROM node:alpine

WORKDIR /usr/src/app

COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/node_modules ./node_modules

EXPOSE 3000

CMD [ "node", "dist/main"]

Step 3: Manage Environment Configuration

It’s crucial to separate production-specific environment configurations which can be handled using environment variables with a .env file or directly in the Dockerfile.

# Add a .env file to your Dockerfile during the build process
COPY .env /usr/src/app/.env

# Or you can define environment variables in the Dockerfile directly
ENV PORT=3000

Step 4: Building and Running the Docker Image

With your Dockerfile in place, you can now build the Docker image and run it as a container.

# To build the image:
docker build -t nestjs-app .

# To run the container:
docker run -p 3000:3000 nestjs-app

Step 5: Implement Health Checks

Incorporate health checks to ensure automated systems can monitor the status of services in a container.

# Adding a health check to your Dockerfile
HEALTHCHECK --interval=30s \
 --timeout=30s \
 CMD node healthcheck.js

Step 6: Integrate with Docker Compose

Use Docker Compose to define and run multi-container Docker applications. Create a docker-compose.yml file to configure your service.

version: '3'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production

Step 7: Use Volumes for Persistent Data

When dealing with databases or files that should persist, volumes are used.

services:
  app:
    ...
  database:
    image: postgres
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Step 8: Setting Up Continuous Integration/Continuous Deployment (CI/CD)

Integrate your Docker workflow into a CI/CD pipeline to automate testing and deployment.

# Sample GitHub Actions configuration for building and pushing a NestJS Docker image
name: Deploy NestJS App

on:
  push:
    branches:
      - master

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Build the Docker image
      run: docker build . --file Dockerfile --tag mynestjsapp
    - name: Push to Registry
      run: docker push mynestjsapp

Conclusion

By following this guide, you have dockerized your NestJS application, making it ready for deployment to a production environment. Embrace containerization for its scalability, portability, and consistency across deployment systems.

Next Article: NestJS Issue: Injected service is undefined in the constructor – A Fix Guide

Previous Article: How to handle form-data in NestJS

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates