Containerized Development Environments That Actually Work
Why we run PostgreSQL, MinIO, and the dev server inside a single Docker container — and how it simplifies onboarding and CI.
By Alex Malahov
Every team has a setup guide. It usually starts with "install Homebrew" and ends with someone debugging a Postgres version mismatch two hours later.
One Container to Rule Them All
Our approach: a single Docker container that includes everything the app needs to run:
- PostgreSQL 16
- MinIO (S3-compatible object storage)
- Bun runtime
- Playwright for E2E testing
- Doppler CLI for secrets
bun run up # start everything
bun run down # stop everythingNo host dependencies beyond Docker. No version conflicts. No "works on my machine."
The Worktree Trick
Each git worktree gets its own container with its own port assignment. You can run multiple feature branches simultaneously without conflicts. The container name, volume, and port are all derived from the worktree path.
Trade-offs
The image build takes 10-15 minutes cold. But you only do it once. After that, bun run up starts in seconds. The productivity gained from zero-friction onboarding far outweighs the initial build time.
When to Use This Pattern
This works well for small-to-medium teams where everyone runs the full stack locally. For larger teams with microservices, you might want a more granular approach. But for a monorepo SaaS — it's hard to beat.