Docker Compose Tip #87: The depends_on options tip #3 didn't cover

Tip #3 stopped at condition: service_healthy. The long-form depends_on syntax has three more fields, each solving a different problem: services: api: build: . depends_on: migrate: condition: service_completed_successfully cache: condition: service_started restart: true metrics: condition: service_started required: false service_completed_successfully: wait for a one-shot to finish service_healthy waits for a long-running service to become ready. service_completed_successfully waits for a service to exit, and only starts the dependent if it exited zero: ...

September 18, 2026 · 2 min · 379 words · Guillaume Lours

Docker Compose Tip #84: Lifecycle hooks now show you why they failed

A failing lifecycle hook, post_start, pre_stop, or the new pre_start, used to report only its exit code: db hook exited with status 1 What the hook actually printed depended on how it ran. Under a plain docker compose up, the output streamed live to the terminal, mixed into the rest of up’s output, but was never carried into the error message itself. Under restart, run, or any tool driving Compose as a library, there was no listener attached at all, so Compose didn’t even request stdout or stderr from the daemon, and there was nothing to read afterward, live or otherwise. Since Compose 5.5.1, both cases keep a tail of the output and fold it straight into the error on failure. ...

September 11, 2026 · 2 min · 371 words · Guillaume Lours

Docker Compose Tip #83: Why up recreated containers that never changed

A service recreates on every single docker compose up. No file change, no rebuild, nothing actually different about the image. Before Compose 5.5.0, that wasn’t a flaky environment, it was a real bug class in how Compose decided an image had changed. One image, three ways to name its digest Compose decides whether to recreate a container by comparing the image’s current identity against a label it recorded last time, com.docker.compose.image. Before 5.5.0, that identity was computed differently depending on how the image got there: ...

September 9, 2026 · 3 min · 578 words · Guillaume Lours

Docker Compose Tip #82: pre_start hooks and native init containers

Tips are back after the summer break, and there are three months of Compose releases to catch up on, v5.2.0 through v5.5.1 shipped while the series was paused. The biggest addition: native init containers, through a new pre_start lifecycle hook. What pre_start does Tip #41 covered post_start and pre_stop, which run a command inside the already-running service container. pre_start is different: each step runs in its own ephemeral container, created after the service container exists but before it starts. It also waits on the service’s own depends_on conditions first, so a step can talk to those dependencies exactly like the main service command does. ...

September 7, 2026 · 4 min · 729 words · Guillaume Lours

Docker Compose Tip #81: tty and stdin_open for interactive containers

Drop a bash or python service into a compose.yaml and it exits immediately on up. The container starts, sees no stdin, prints nothing, and stops. The fix is the Compose equivalent of docker run -it: tty: true and stdin_open: true. What each flag does The two flags map directly to the docker run flags everyone has typed a thousand times: stdin_open: true ⇔ docker run -i — keep STDIN open even when not attached. tty: true ⇔ docker run -t — allocate a pseudo-TTY. services: shell: image: alpine command: sh stdin_open: true tty: true Set both for an interactive shell. Set only tty: true for a process that wants a terminal (for color output, line-buffered logs) but doesn’t read from stdin. stdin_open: true alone is rare — almost always paired with tty. ...

June 26, 2026 · 3 min · 610 words · Guillaume Lours