Dockerizing Your Node.js App: A Step-by-Step Developer Guide
2025-08-14
Dockerizing Your Node.js App: A Step-by-Step Developer Guide
Shipping "works on my machine" code is a thing of the past. Docker guarantees your app behaves the same everywhere—CI, staging, production.
This guide walks you through:
- Writing a minimal
Dockerfile. - Using multi-stage builds for smaller images.
- Live-reloading with docker-compose.
- Debugging inside containers.
1. Project Structure
my-app/
├─ src/
│ └─ index.js
├─ package.json
└─ Dockerfile
2. Create a Minimal Dockerfile
# 1️⃣ Base image
FROM node:20-alpine AS base
# 2️⃣ Set work directory
WORKDIR /app
# 3️⃣ Copy dependencies first for cache
COPY package*.json ./
RUN npm ci --omit=dev
# 4️⃣ Copy source code
COPY . .
# 5️⃣ Expose port & run
EXPOSE 3000
CMD ["node", "src/index.js"]
👉 Why alpine? ~50 MB smaller than Debian variants, faster pulls.
3. Multi-Stage for Production
# Build stage
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build # transpile TS / bundle
# Runtime stage
FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY package*.json ./
RUN npm ci --omit=dev
EXPOSE 3000
CMD ["node", "dist/index.js"]
4. docker-compose for Local Dev (Hot Reload)
auth-service:
build: .
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
command: npm run dev
Mounting the codebase + nodemon gives instant reloads without rebuilding the image.
5. Debugging Inside a Container
- Add
--inspect=0.0.0.0to your start script. - Expose debug port
9229in Docker. - Attach VS Code Remote-Containers or Chrome DevTools.
6. Optimizing Image Size
- Use
.dockerignore– excludenode_modules, tests, docs. - Prefer
npm ci --omit=dev. - Leverage Slim or Distroless base images for prod.
Cheatsheet
| Command | Purpose |
|---|---|
docker build -t my-app . | Create image |
docker run -p 3000:3000 my-app | Start container |
docker compose up --build | Build & run services |
docker system prune -f | Clean dangling images |
Happy shipping!