How to containerize Node.js with Docker

Containerizing Node.js applications with Docker ensures consistent environments across development, testing, and production. With over 12 years of Node.js experience since 2014 and as the creator of CoreUI, I’ve Dockerized numerous production Node.js services. Docker containers package applications with their dependencies, making deployment reliable and portable across different environments. This approach simplifies deployment, scaling, and environment management for Node.js applications.

Use Docker multi-stage builds to create optimized, secure Node.js containers for production deployment.

Basic Dockerfile:

# Dockerfile
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./

RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["node", "index.js"]

Multi-stage build:

# Dockerfile
# Build stage
FROM node:20-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build
RUN npm prune --production

# Production stage
FROM node:20-alpine

WORKDIR /app

# Copy only necessary files
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist

ENV NODE_ENV=production
EXPOSE 3000

# Run as non-root user
USER node

CMD ["node", "dist/index.js"]

Docker Compose:

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - '3000:3000'
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://db:5432/myapp
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

.dockerignore:

node_modules
npm-debug.log
.env
.git
.gitignore
README.md
.vscode
coverage
.nyc_output
dist
build

Development Dockerfile:

# Dockerfile.dev
FROM node:20

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000

CMD ["npm", "run", "dev"]

Best Practice Note

Use Alpine images for smaller container size. Implement multi-stage builds to reduce final image size. Copy package files first to leverage Docker layer caching. Run as non-root user for security. Use .dockerignore to exclude unnecessary files. This is how we containerize CoreUI Node.js services—optimized Docker images with multi-stage builds ensuring small, secure, production-ready containers.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author