Node.js8 min read

Docker for Node.js Applications

Containerize Node.js apps with Docker. Learn Dockerfile, docker-compose, and deployment best practices.

Sarah Chen
December 19, 2025
0.0k0

Docker for Node.js Applications

Docker packages your app with its dependencies. Works on my machine = works everywhere.

Basic Dockerfile

# Dockerfile
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./

RUN npm ci --only=production

COPY . .

EXPOSE 3000

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

Build and Run

# Build image
docker build -t my-app .

# Run container
docker run -p 3000:3000 my-app

# Run with environment variables
docker run -p 3000:3000 -e NODE_ENV=production my-app

# Run in background
docker run -d -p 3000:3000 my-app

Optimized Dockerfile

# Use specific version
FROM node:20-alpine AS builder

WORKDIR /app

# Copy package files first (better caching)
COPY package*.json ./

# Install all dependencies for build
RUN npm ci

# Copy source
COPY . .

# Build if needed (TypeScript, etc.)
RUN npm run build

# Production stage
FROM node:20-alpine

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install production dependencies only
RUN npm ci --only=production && npm cache clean --force

# Copy built files from builder
COPY --from=builder /app/dist ./dist

# Security: run as non-root user
USER node

EXPOSE 3000

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

.dockerignore

node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
Dockerfile
docker-compose.yml
.dockerignore
README.md
.nyc_output
coverage

Docker Compose

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=mongodb://mongo:27017/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - mongo
      - redis
    restart: unless-stopped

  mongo:
    image: mongo:6
    volumes:
      - mongo-data:/data/db
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  mongo-data:

Run with Compose

# Start all services
docker-compose up

# Start in background
docker-compose up -d

# View logs
docker-compose logs -f app

# Stop all
docker-compose down

# Stop and remove volumes
docker-compose down -v

Development with Docker

# docker-compose.dev.yml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules  # Don't override node_modules
    environment:
      - NODE_ENV=development
    command: npm run dev
# Dockerfile.dev
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

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

Health Checks

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1
// Express health endpoint
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

Multi-Stage for TypeScript

FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]

Common Commands

# List containers
docker ps

# Stop container
docker stop <container_id>

# Remove container
docker rm <container_id>

# List images
docker images

# Remove image
docker rmi <image_id>

# Shell into container
docker exec -it <container_id> sh

# View logs
docker logs <container_id>

Key Takeaway

Docker ensures consistent environments. Use multi-stage builds for smaller images. Use docker-compose for multi-service apps. Include health checks. Use non-root user for security. Keep images small with Alpine.

#Node.js#Docker#DevOps#Deployment#Advanced