Docker Compose Patterns I Actually Use

Six compose patterns that survive production: healthchecks, depends_on with conditions, profiles, and restart semantics.

·2 min read
dockerhomelab

Docker Compose is the lingua franca of self-hosting. After running a homelab for three years, six patterns have survived every refactor.

1. Healthchecks Are Not Optional

Without a healthcheck, Compose has no way to know whether a container is actually serving traffic — only that the process hasn’t exited. A database that’s stuck in crash-loop recovery will look “healthy” to depends_on.

services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      timeout: 3s
      retries: 5

2. depends_on With Conditions

The bare depends_on: [db] only waits for the container to start. Pair it with a service condition to wait until the dependency is genuinely ready:

api:
  depends_on:
    db:
      condition: service_healthy

This single change eliminates an entire class of “first boot fails, retry works” bugs.

3. Compose Profiles

A single compose.yaml can serve multiple environments with profiles:

services:
  app: { ... }
  debug-tools:
    profiles: [debug]
    image: nicolaka/netshoot

docker compose up starts the app; docker compose --profile debug up adds the troubleshooting sidecar.

4. Restart Policies

restart: unless-stopped is almost always what you want. always will re-launch containers after a reboot even if you deliberately stopped them, which is rarely the intent on a development machine.

5. Named Volumes Over Bind Mounts for State

Bind mounts are convenient for source code but treacherous for databases — filesystem permission and ownership semantics will eventually bite. Use named volumes for anything you can’t recreate from a config file.

6. One Compose File, Many Overlays

The -f flag composes multiple files. Keep a base compose.yaml for the service definitions and a compose.production.yaml that overrides labels, resource limits, and networks. This keeps environment-specific noise out of the main file.

Wrapping Up

These patterns aren’t exotic — they’re the boring defaults I keep coming back to. The unifying principle: make the system’s actual state match what Compose thinks it is.