Docker for Node.js Applications
Containerize Node.js apps with Docker. Learn Dockerfile, docker-compose, and deployment best practices.
Docker for Node.js Applications
Docker packages your app with its dependencies. Works on my machine = works everywhere.
Basic Dockerfile
```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
```bash # 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
```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
```yaml # 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
```bash # 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
```yaml # 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 # Dockerfile.dev FROM node:20-alpine
WORKDIR /app
COPY package*.json ./ RUN npm install
COPY . .
CMD ["npm", "run", "dev"] ```
Health Checks
```dockerfile HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1 ```
```javascript // Express health endpoint app.get('/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }); }); ```
Multi-Stage for TypeScript
```dockerfile 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
```bash # 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.