Claude Code Docker Compose Development (2026)
Docker Compose has become an essential tool for developers managing multi-container applications. When combined with Claude Code, you get a powerful development environment where AI assistance handles container orchestration, debugging, and service configuration while you focus on writing code. This guide shows you how to build an efficient development workflow using Claude Code with Docker Compose, covering everything from initial setup to production-ready patterns.
Setting Up Your Development Environment
The foundation of a solid Docker Compose workflow starts with a well-structured project. Your directory layout should separate concerns between your application code and container configuration. A more complete project structure looks like this:
my-project/
docker-compose.yml
docker-compose.override.yml
docker-compose.prod.yml
Dockerfile
Dockerfile.dev
src/
api/
workers/
tests/
unit/
integration/
scripts/
entrypoint.sh
wait-for-it.sh
.env
.env.example
.dockerignore
The .dockerignore file is often overlooked but matters for build performance. It prevents large directories like node_modules, .git, and test output from being sent to the Docker build context:
node_modules
.git
.env
*.log
coverage/
dist/
When you invoke Claude Code to help with this setup, describe your stack clearly. For example, if you’re building a web application with a database and caching layer, specify each service:
claude "Create a docker-compose.yml with a Node.js API service, PostgreSQL database, and Redis cache. Include proper volume mounts for development, health checks, and dependency ordering."
Claude Code generates a Compose file tailored to your requirements, including health checks and depends_on conditions that prevent your API from starting before the database is ready. You can then refine it interactively: ask Claude to add a worker service, change the base image, or configure resource limits.
Essential Docker Compose Commands for Development
Claude Code excels at translating your intent into precise Docker commands. Here are the workflows you’ll use most frequently:
Starting your development environment:
docker-compose up -d
Starting and watching logs immediately:
docker-compose up
Rebuilding images when your Dockerfile changes:
docker-compose up -d --build
Viewing logs from all services:
docker-compose logs -f
Viewing logs from a single service:
docker-compose logs -f api
Accessing a specific service shell:
docker-compose exec api sh
or for bash if available
docker-compose exec api bash
Running a one-off command without starting the service:
docker-compose run --rm api npm run migrate
Stopping without removing containers:
docker-compose stop
Stopping and removing containers, networks, and volumes:
docker-compose down -v
The difference between stop and down -v matters: stop preserves your database volume so data persists across restarts, while down -v wipes everything for a clean slate. Use down -v when you need to reset test state or clear a corrupted database.
When you’re stuck on a Docker issue, describe the problem to Claude. If your containers fail to start or you encounter networking problems, paste the error output and ask for troubleshooting steps. Claude can analyze the error messages and suggest fixes. whether it’s a port conflict, missing environment variable, or volume mounting issue.
Complete docker-compose.yml for a Production-Grade Dev Stack
Below is a realistic, full-featured Compose file for a Node.js API with PostgreSQL, Redis, and a background worker. This is the kind of output you can ask Claude to generate for you:
version: "3.9"
services:
api:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "${API_PORT:-3000}:3000"
volumes:
- ./src:/app/src
- /app/node_modules
environment:
- NODE_ENV=development
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
worker:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/app/src
- /app/node_modules
environment:
- NODE_ENV=development
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
- REDIS_URL=redis://cache:6379
command: npm run worker
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
ports:
- "5432:5432"
cache:
image: redis:7-alpine
volumes:
- redis_data:/data
command: redis-server --appendonly yes
ports:
- "6379:6379"
volumes:
postgres_data:
redis_data:
The service_healthy condition on depends_on is critical. Without it, your API container starts immediately after PostgreSQL’s container starts, but the database process inside may not be accepting connections yet. The health check ensures your API only starts when the database is truly ready.
Integrating Claude Skills for Docker Workflows
Several Claude skills enhance your Docker Compose development:
- tdd: Write tests alongside your containerized services
- pdf: Generate documentation about your architecture
- frontend-design: Design UIs that run in development containers
- supermemory: Recall Docker troubleshooting solutions across projects
The tdd skill pairs well with Docker Compose because you can run tests inside containers without polluting your host system. Define a test service in your Compose file that shares the same build but runs in test mode:
services:
api:
build: .
volumes:
- ./src:/app/src
command: npm run dev
test:
build: .
volumes:
- ./src:/app/src
- ./tests:/app/tests
command: npm test
environment:
- NODE_ENV=test
- DATABASE_URL=postgres://test_user:test_pass@db_test:5432/test_db
depends_on:
db_test:
condition: service_healthy
db_test:
image: postgres:16-alpine
environment:
- POSTGRES_DB=test_db
- POSTGRES_USER=test_user
- POSTGRES_PASSWORD=test_pass
tmpfs:
- /var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U test_user -d test_db"]
interval: 5s
timeout: 3s
retries: 10
Using tmpfs for the test database stores data in memory rather than on disk. Integration tests run faster and the database resets automatically each time the container stops.
Run your test container in isolation: docker-compose run --rm test. This approach keeps your testing environment identical across all team members regardless of their local setup.
Debugging Containerized Applications
Debugging inside Docker containers requires a different approach than local development. Here is a structured way to diagnose the most common failure modes with Claude’s help:
Container exits immediately
Check logs with docker-compose logs service-name. The most common causes are missing dependencies, syntax errors in environment variables, or an entrypoint script exiting non-zero. Paste the full log output to Claude for analysis.
docker-compose logs api --tail=50
Network connectivity issues
In Docker Compose, services communicate using their service names as hostnames. not localhost. If your API tries to connect to localhost:5432, it fails because Postgres is in a different container. The correct connection string is:
postgres://user:password@db:5432/myapp
You can verify DNS resolution from inside a container:
docker-compose exec api nslookup db
docker-compose exec api curl -v http://cache:6379
Permission problems on volume mounts
Containers often run as a non-root user, but mounted host files may have different ownership. Fix this by matching UIDs in your Dockerfile:
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup package*.json ./
RUN npm ci
COPY --chown=appuser:appgroup . .
USER appuser
Port already in use
When a port is taken, Docker fails with Bind for 0.0.0.0:5432 failed: port is already allocated. Find what process holds it and either stop that process or change the host-side port mapping in Compose:
Find the process using port 5432
lsof -i :5432
Then kill it or change the Compose mapping to "5433:5432"
When debugging, provide Claude with specific error messages and your Compose configuration. The more context you give, the more accurate the troubleshooting guidance.
Environment Configuration Best Practices
Environment variables are critical for Docker Compose workflows. A well-organized .env file covers all services:
.env file. never commit this
Application
API_PORT=3000
NODE_ENV=development
Database
POSTGRES_DB=myapp
POSTGRES_USER=developer
POSTGRES_PASSWORD=dev_password_change_me
Redis
REDIS_PASSWORD=
Feature flags
ENABLE_EMAIL_VERIFICATION=false
LOG_LEVEL=debug
Reference these in your Compose file using variable substitution with defaults:
services:
api:
build: .
ports:
- "${API_PORT:-3000}:3000"
environment:
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
- LOG_LEVEL=${LOG_LEVEL:-info}
depends_on:
- db
db:
image: postgres:16-alpine
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
The :- default syntax (${API_PORT:-3000}) provides a fallback when the variable is not set, making the Compose file usable without a .env file in some contexts.
Never commit .env to version control. Add it to .gitignore and maintain a .env.example with placeholder values and comments:
.env.example. commit this, it documents required variables
API_PORT=3000
NODE_ENV=development
POSTGRES_DB=myapp
POSTGRES_USER=developer
POSTGRES_PASSWORD=CHANGE_ME
REDIS_PASSWORD=
LOG_LEVEL=debug
Optimizing Development Speed
Slow builds and restarts kill developer productivity. These patterns keep iteration fast:
Multi-stage Dockerfiles for dev vs. production
A Dockerfile.dev installs dev dependencies and uses nodemon for hot reloading:
FROM node:20-alpine AS base
WORKDIR /app
COPY package*.json ./
FROM base AS development
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
FROM base AS production
RUN npm ci --only=production
COPY src/ ./src/
CMD ["node", "src/index.js"]
Hot-reload volume mounts
services:
api:
build:
context: .
dockerfile: Dockerfile.dev
target: development
volumes:
- ./src:/app/src
- /app/node_modules
environment:
- NODE_ENV=development
- CHOKIDAR_USEPOLLING=true
The anonymous volume /app/node_modules prevents the host’s node_modules directory (or its absence) from overwriting the container’s installed packages. CHOKIDAR_USEPOLLING=true is needed on some macOS and Windows hosts where inotify events do not propagate into containers reliably.
Comparison: volume mount strategies
| Strategy | Use case | Tradeoff |
|---|---|---|
./src:/app/src (bind mount) |
Source code hot reload | Slightly slower I/O on macOS |
Named volume for node_modules |
Preserve container packages | Cannot inspect from host easily |
tmpfs for test database |
Fast throwaway test DB | Data lost on container stop |
| Anonymous volume | Ephemeral scratch space | Cannot be reused across runs |
| No volume (copy only) | Production builds | Immutable, no live reload |
Managing Multiple Projects
As you work on multiple Docker Compose projects simultaneously, container and network names collide unless you use project names. There are two ways to set the project name:
Using the -p flag:
docker-compose -p myproject up -d
docker-compose -p myproject logs -f
docker-compose -p myproject down
Using the COMPOSE_PROJECT_NAME variable in .env:
COMPOSE_PROJECT_NAME=myproject
Setting it in .env is more convenient because every docker-compose command in that directory automatically uses the right project name without extra flags.
To see all running Compose projects at a glance:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
You can also use docker-compose ls (available in Compose v2) to list active projects:
docker compose ls
The supermemory skill helps you remember project-specific Docker configurations across different work sessions. Ask Claude to index your Compose files, common debugging patterns, and the specific quirks of each project so you can retrieve them by name in future sessions.
Splitting Configuration with Override Files
Docker Compose supports layered configuration through override files. The base docker-compose.yml defines the canonical architecture, while environment-specific files add or change settings without touching the base:
docker-compose.yml (base. committed):
services:
api:
build: .
environment:
- NODE_ENV=production
db:
image: postgres:16-alpine
docker-compose.override.yml (dev. committed, auto-merged):
services:
api:
build:
dockerfile: Dockerfile.dev
volumes:
- ./src:/app/src
- /app/node_modules
environment:
- NODE_ENV=development
ports:
- "3000:3000"
db:
ports:
- "5432:5432"
docker-compose.prod.yml (production. explicit):
services:
api:
image: myregistry/myapp:${IMAGE_TAG}
deploy:
replicas: 2
resources:
limits:
cpus: "0.5"
memory: 512M
Run production locally for testing:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
This pattern keeps your development ergonomics (exposed ports, volume mounts, debug logging) completely separate from production concerns (resource limits, image tags, replica counts).
Production Considerations
While Docker Compose excels at local development, production deployments typically use Kubernetes or managed container services. However, your Compose files still serve as valuable documentation for your architecture and can drive CI/CD pipelines.
Using Compose in CI pipelines
GitHub Actions can spin up your full stack to run integration tests:
.github/workflows/test.yml
jobs:
integration-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start services
run: docker-compose -f docker-compose.yml -f docker-compose.test.yml up -d
- name: Wait for health checks
run: docker-compose run --rm wait
- name: Run integration tests
run: docker-compose run --rm test
- name: Collect logs on failure
if: failure()
run: docker-compose logs
- name: Tear down
if: always()
run: docker-compose down -v
Use the pdf skill to generate architecture documentation from your Compose configuration:
claude "Use the pdf skill to create an architecture diagram from this docker-compose.yml showing service relationships, dependencies, port mappings, and data flows."
Keep development and production configurations separate using the override pattern described above. This avoids the common mistake of accidentally running production containers with development volume mounts that expose source code.
Compose v1 vs. Compose v2 command syntax
| Action | Compose v1 | Compose v2 |
|---|---|---|
| Start services | docker-compose up |
docker compose up |
| List projects | Not available | docker compose ls |
| Copy files | docker-compose cp |
docker compose cp |
| Profile support | Limited | --profile flag |
| Config merge | Manual | docker compose config |
Compose v2 ships as a Docker CLI plugin (note: no hyphen in docker compose). It is the current standard and adds features like profiles, which let you define optional services that only start when requested:
services:
api:
build: .
adminer:
image: adminer
profiles: ["tools"]
ports:
- "8080:8080"
Start everything including tools: docker compose --profile tools up -d. By default, docker compose up -d starts only api, keeping your dev environment lean.
Conclusion
Claude Code transforms Docker Compose from a manual orchestration tool into an intelligent development partner. By describing your goals and problems in natural language, you get actionable Docker commands, debugging guidance, and complete Compose configurations tailored to your stack. The key practices covered here. layered override files, health check dependencies, hot-reload volume mounts, per-project naming, and CI integration. make the difference between a fragile local setup and one that works consistently across your entire team. Combined with skills like tdd for containerized testing, pdf for architecture documentation, and supermemory for knowledge retention, you build a development workflow that is both powerful and maintainable from day one.
Try it: Paste your error into our Error Diagnostic for an instant fix.
Related Reading
- Claude Code DevOps Engineer Docker Container Workflow Tips
- Claude Code Docker Compose API Tutorial Guide
- Claude Code Docker Compose Production Guide
- Claude Code Azure Functions Development Workflow
- Claude Code Docker Secrets Management Guide
- How to Use GitHub Actions OIDC Workflow (2026)
- Claude Code GitHub Actions Environment Protection
- Claude Code for Helm Hooks Workflow Tutorial
- Claude Code GitHub Actions Composite Actions
- Claude Code For Act Local GitHub — Complete Developer Guide
Built by theluckystrike. More at zovo.one
Find the right skill → Browse 155+ skills in our Skill Finder.