Docker Containerization: From Development to Production
DevOps

Docker Containerization: From Development to Production

M

Md Nayeem Hossain

Author

Dec 18, 2024
11 min read

Docker Containerization for Developers

"It works on my machine" is a phrase every developer hates hearing. Docker solves this by packaging your application and all its dependencies into a standard unit called a container.

In this guide, I'll explain how to Dockerize a Node.js application properly, from a development setup with hot-reloading to an optimized production build.

The Dockerfile

The Dockerfile is the blueprint for your container. A common mistake is including unnecessary files in the final image, making it huge. We can use Multi-stage Builds to fix this.

We compile and build the app in a "builder" stage, and then copy *only* the necessary artifacts to a final, slim "production" stage.

dockerfile
# Stage 1: Builder
# We use a larger image with all build tools
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Production
# We use a clean, small image
FROM node:20-alpine AS production
WORKDIR /app
ENV NODE_ENV=production

# Security: Don't run as root!
USER node

# Copy only what we need from the builder stage
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

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

Docker Compose for Development

Running containers manually is tedious. Docker Compose allows you to define your entire stack (App, Database, Redis) in one file.

This setup below mounts your local code into the container, so when you save a file, the app updates instantly (Hot Reloading), just like running it locally!

yaml
version: '3.8'

services:
  app:
    build: 
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    # This volume mapping enables hot-reloading
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - DATABASE_URL=mongodb://mongo:27017/myapp
    depends_on:
      - mongo

  mongo:
    image: mongo:7
    ports:
      - "27017:27017"
    volumes:
      - mongo_data:/data/db

volumes:
  mongo_data:

Production Best Practices

  • Use Specific Tags: Never use :latest in production. Use specific versions (e.g., node:20.9.0-alpine) to ensure your build is reproducible.
  • Health Checks: Add a HEALTHCHECK instruction so Docker (or Kubernetes) knows if your app is stuck or crashing.
  • Secrets: Never bake secrets (API keys, passwords) into the image. Pass them as environment variables at runtime.
  • dockerfile
    # Add this to your Dockerfile
    HEALTHCHECK --interval=30s --timeout=3s \
      CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
    Docker
    DevOps
    Containers
    Deployment

    © 2026 Md Nayeem Hossain. All rights reserved.