Docker Compose for Local Development: Patterns That Work
Docker Compose makes local development environments reproducible. Here are patterns that make them actually pleasant to use.
Separate Dev and Production Configs
Use compose.yml for shared configuration and compose.override.yml for development-specific settings. Docker Compose merges them automatically. The override file adds volume mounts for hot reloading, debug ports, and development environment variables.
Hot Reloading With Volumes
Mount your source code as a volume so changes appear instantly in the container. Combine with a file watcher like nodemon for Node.js or watchfiles for Python. Add a develop.watch section in your compose file for Docker Compose Watch support.
Database Seeding
Create an init script directory mounted to your database container. PostgreSQL reads .sql files from /docker-entrypoint-initdb.d/ on first start. Use this for schema creation and seed data. Store seed files in your repository so every team member gets the same starting data.
Health Checks and Dependencies
Use healthcheck definitions and depends_on with condition: service_healthy to ensure services start in the right order. This prevents your app from crashing because the database is not ready yet.
Debugging Containers
Expose debug ports in your override file. For Node.js, add --inspect=0.0.0.0:9229 and map port 9229. Attach your IDE debugger to the mapped port. For database inspection, expose the database port only in development.
Cleanup Patterns
Use named volumes for data persistence and docker compose down -v to reset everything. Create Makefile targets for common operations: make up, make down, make reset, make logs. This reduces the Docker Compose commands your team needs to remember.
Related Posts
Sponsor Our Newsletter
Reach thousands of developers who are actively evaluating AI tools, MCP servers, and dev infrastructure. Our weekly newsletter goes to engaged technical decision-makers.
All sponsored content is clearly labeled per our editorial policy.