Setting Up Dev Environments
Setting Up Dev Environments
The Problem
"Works on my machine" — developers have different OS, versions, dependencies, and configurations. Docker eliminates this by packaging everything into containers.
Basic Dev Dockerfile
# Dockerfile.dev
FROM node:20
# Install global tools
RUN npm install -g nodemon
WORKDIR /app
# Copy package files first (cache layer)
COPY package*.json ./
RUN npm install
# Copy source code
COPY . .
EXPOSE 3000
# Use nodemon for auto-restart
CMD ["nodemon", "server.js"]
docker-compose.dev.yml
services:
api:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app # Bind mount source code
- /app/node_modules # Anonymous volume (don't mount host node_modules)
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- DEBUG=app:*
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_DB: myapp_dev
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dev"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
pgdata:
redis_data:
Start Development
# Start dev environment
docker compose -f docker-compose.dev.yml up -d
# View logs
docker compose -f docker-compose.dev.yml logs -f api
# Execute into container
docker compose -f docker-compose.dev.yml exec api bash
# Run tests
docker compose -f docker-compose.dev.yml exec api npm test
# Stop environment
docker compose -f docker-compose.dev.yml down
# Stop and reset database
docker compose -f docker-compose.dev.yml down -v
VS Code Dev Containers
VS Code Dev Containers
What are Dev Containers?
Dev Containers use Docker to create fully configured development environments with VS Code. The IDE runs on the host, but the terminal, extensions, and toolchain run inside the container.
.devcontainer/devcontainer.json
{
"name": "My Project",
"dockerComposeFile": "docker-compose.dev.yml",
"service": "api",
"workspaceFolder": "/app",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-vscode.vscode-typescript-next",
"humao.rest-client"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
},
"postCreateCommand": "npm install",
"postStartCommand": "npm run dev",
"forwardPorts": [3000, 5432, 6379],
"remoteUser": "node"
}
.devcontainer/docker-compose.dev.yml
services:
api:
build:
context: ..
dockerfile: Dockerfile.dev
volumes:
- ..:/app:cached
- /app/node_modules
command: sleep infinity # Keep container running for VS Code
db:
image: postgres:16
environment:
POSTGRES_DB: myapp_dev
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
redis:
image: redis:7-alpine
Setup Steps
- Install VS Code Extension: "Dev Containers"
- Open project in VS Code
- Press
Ctrl+Shift+P→ "Dev Containers: Reopen in Container" - VS Code connects to the container and installs extensions
- Terminal runs inside the container with all tools
Benefits
- Every team member gets the same environment
- New developers are productive in minutes
- No local toolchain setup required
- Consistent CI/CD (same container used for dev and CI)
Dev Container Features
{
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "20" },
"ghcr.io/devcontainers/features/python:1": { "version": "3.12" },
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
}
}
Multi-Language Dev Environments
Multi-Language Dev Environments
Node.js + Python
services:
frontend:
build:
context: ./frontend
dockerfile: Dockerfile.dev
volumes:
- ./frontend:/app
- /app/node_modules
ports:
- "3000:3000"
backend:
build:
context: ./backend
dockerfile: Dockerfile.dev
volumes:
- ./backend:/app
- /app/.venv
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
volumes:
pgdata:
Python Backend Dockerfile.dev
FROM python:3.12-slim
WORKDIR /app
RUN pip install poetry
COPY pyproject.toml poetry.lock ./
RUN poetry install --no-root
COPY . .
CMD ["poetry", "run", "uvicorn", "main:app", "--reload", "--host", "0.0.0.0"]
Go Backend Dockerfile.dev
FROM golang:1.21
WORKDIR /go/src/app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
CMD ["go", "run", "main.go"]
Java Spring Boot Dockerfile.dev
FROM eclipse-temurin:21-jdk-jammy
WORKDIR /app
COPY gradlew build.gradle settings.gradle ./
COPY gradle gradle
RUN ./gradlew dependencies --no-daemon
COPY src src
CMD ["./gradlew", "bootRun", "--continuous", "--no-daemon"]
Development Best Practices
services:
api:
build:
target: development # Multi-stage: use dev stage
volumes:
# Named volume for deps (avoids permission issues)
- node_modules:/app/node_modules
# Bind mount source (live reload)
- ./src:/app/src
# Bind mount config (read-only)
- ./config:/app/config:ro
environment:
- NODE_ENV=development
- DEBUG=app:*
# Don't use restart: always in dev (annoying for debugging)
volumes:
node_modules: