How to Dockerize a NestJS API

By Abdelilah Ommane ยท Backend Developer

Short answer

Add a Dockerfile with a multi-stage build (install → build → run), add a .dockerignore, then run it with docker build and docker run -p 3000:3000. For a real project, use docker-compose.yml to also spin up PostgreSQL.

1. Create a multi-stage Dockerfile

# syntax=docker/dockerfile:1
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine AS prod
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/main"]

2. Add a .dockerignore

node_modules
dist
.git
.env
npm-debug.log

3. Build and run

docker build -t nest-api .
docker run -p 3000:3000 nest-api

4. Add PostgreSQL with Docker Compose

version: "3.8"
services:
  api:
    build: .
    ports: ["3000:3000"]
    environment:
      - DATABASE_URL=postgres://postgres:postgres@db:5432/app
    depends_on: [db]
  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=app
    ports: ["5432:5432"]

FAQ

Why a multi-stage build?

It keeps the final image small โ€” dev dependencies and the source TypeScript never ship to the production image, only the compiled dist and runtime packages.

Should I run migrations in the container?

Run schema migrations as a separate one-off step (docker compose run api npx typeorm migration:run) or as an init job, not on every container start, to avoid race conditions with multiple replicas.

← All guides