Workflows — The Daily Kitchen Routine
The five friends have learned the commands and written their recipes. Now they need a routine — a shared way of working that keeps every developer's kitchen consistent and every deployment predictable.
The Core Loop
The loop has three rules:
- Develop inside containers — no "works on my machine" ever again
- Build once, run anywhere — the image is the same on every machine
- One container per service — web server, database, and cache each get their own
If you ever hear "it works on my machine," the answer is always: "then let's ship your machine."
Local Development — Your Personal Kitchen
The Problem
Without Docker, each developer installs a different version of Node, Postgres, Redis, and a dozen other tools directly on their laptop. When something breaks, nobody knows why.
The Solution
services:
web:
build: .
ports:
- "3000:3000"
volumes:
- .:/app # Live-reload: your code changes appear instantly
- /app/node_modules # Don't overwrite node_modules with local copy
environment:
- NODE_ENV=development
depends_on:
- db
- redis
db:
image: postgres:16
environment:
POSTGRES_DB: campus_library
POSTGRES_USER: riya
POSTGRES_PASSWORD: secret
ports:
- "5432:5432"
volumes:
- db-data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
db-data:
docker compose up -d
docker compose ps
NAME IMAGE STATUS PORTS
web campus-lib Up 2 minutes 0.0.0.0:3000->3000/tcp
db postgres:16 Up 2 minutes 0.0.0.0:5432->5432/tcp
redis redis:7 Up 2 minutes 0.0.0.0:6379->6379/tcp
The volumes mount (.:/app) means your local code changes are reflected inside the container instantly — no rebuild needed for code changes.
Rebuilding — When the Recipe Changes
If you change package.json (add a dependency), you need to rebuild:
docker compose build
docker compose up -d
Or force a full rebuild:
docker compose build --no-cache
docker compose up -d
Forgetting docker compose build after changing dependencies means the container still uses the old node_modules. If a new package isn't found, rebuild.
Production Images — The Catering Order
When the friends are ready to ship, they build a production image — a minimal, optimized version:
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]
docker build -t campus-library:1.0.0 .
Tag your production images with a version (1.0.0, not just latest). This makes rollbacks trivial — just point back to the previous tag.
Pushing to a Registry — Sharing the Recipe
A container registry (Docker Hub, AWS ECR, GitHub Container Registry) is a shared shelf where everyone can store and pull images.
docker tag campus-library:1.0.0 riya/campus-library:1.0.0
docker push riya/campus-library:1.0.0
docker pull riya/campus-library:1.0.0
docker run -d -p 3000:3000 riya/campus-library:1.0.0
docker push uploads your image to the registry. docker pull downloads it. This is how images travel from your laptop to a production server.
Environment Management — Different Kitchens for Different Meals
Using .env files
APP_PORT=3000
DB_PASSWORD=secret
NODE_ENV=development
services:
web:
ports:
- "${APP_PORT}:3000"
env_file:
- .env
Override files
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Use .env files for local development secrets. Never commit .env to Git — add it to .gitignore.
Health Checks — Testing the Lunch Box
Docker can automatically check if a container is healthy:
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:3000/health || exit 1
services:
web:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 3s
retries: 3
docker inspect --format='{{.State.Health.Status}}' my-web
healthy
Health checks are the quality inspector. They catch problems before users do.
Cleanup — Washing the Dishes
docker compose down
docker compose down -v
docker system prune -a --volumes
docker compose down -v deletes all data in named volumes. Only use it when you truly want a fresh start.