How to Dockerize a NestJS API
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.