It is safe to assume that Docker shows up at some point in every developer's life. We often reach for compose.yaml files to run our applications and their dependencies locally, and sometimes even in production.

Real projects tend to need more than "start these containers". You may need to run a database migration before the app boots, guarantee the database is actually ready to accept connections, spin up only a subset of your dependencies, and so on. In many teams I have seen these requirements solved with shell scripts that not everyone is comfortable with, which creates friction and a fear of touching them. With that in mind, I want to shine a light on a few Docker Compose features that are frequently overlooked, and put them together following current best practices.

Before the good parts, a quick note on the conventions used throughout this article.

Conventions used here

Files are named compose.yaml and invoked with the docker compose plugin.