Compose Service
A named container definition in a Docker Compose file that specifies the image, ports, environment, volumes, dependencies, and runtime configuration for one component of a multi-container application.
Compose Service — One Component of Your Application Stack
What Is a Compose Service in Simple Terms?
In Docker Compose, a service is one named component of your application. Your application might have three services: api, postgres, and redis. Each service definition tells Docker exactly how to run that component — which image to use, which ports to expose, which environment variables to set, which volumes to mount, and which other services it depends on.
A Complete Service Definition
version: "3.8" services: payment-api: # <- service name (also DNS hostname) image: payment-api:v3.1.0 ports: - "8080:8080" environment: DB_HOST: postgres # reaches postgres service by name depends_on: postgres: condition: service_healthy restart: unless-stopped deploy: resources: limits: cpus: "1.5" memory: 512M healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 5s retries: 3 postgres: image: postgres:15-alpine environment: POSTGRES_PASSWORD: secret volumes: - postgres-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s retries: 5 volumes: postgres-data:All Service Configuration Keys
services: myservice: image: myimage:tag # image to use build: . # or build from Dockerfile container_name: myservice # fixed container name ports: - "8080:80" environment: KEY: value env_file: - .env volumes: - data:/app/data - ./config:/app/config:ro networks: - mynetwork depends_on: other: condition: service_healthy restart: unless-stopped command: ["node", "server.js"] # override CMD entrypoint: ["/entrypoint.sh"] # override ENTRYPOINT working_dir: /app user: "1000:1000" read_only: true tmpfs: - /tmp logging: driver: json-file options: max-size: "100m" deploy: resources: limits: cpus: "1" memory: 512M profiles: - debug # only starts when debug profile activeService Scaling
# Scale a service to 3 instancesdocker compose up -d --scale payment-api=3 # IMPORTANT: remove container_name before scaling# A fixed container_name conflicts when scaling to multiple instances # Check which instances are runningdocker compose ps# NAME STATUS# project-api-1 Up# project-api-2 Up# project-api-3 UpService Discovery Between Services
Every service name in Compose is automatically a DNS hostname reachable by every other service on the same project network:
# Verify from inside one running servicedocker compose exec payment-api ping postgres# PING postgres (172.20.0.3) — resolves automaticallyQuick Reference & Troubleshooting Commands
| Problem | Cause | Fix |
|---|---|---|
| Service fails to scale | container_name is set |
Remove container_name from the service block |
| Service can't reach another by name | Services on different networks | Add both to the same networks: entry |
| Env vars missing inside container | Wrong key under environment |
docker compose exec <svc> env to verify |
| Service starts before dependency is ready | No health check condition | Add depends_on.<svc>.condition: service_healthy |
| Resource limits ignored | Using plain docker compose up (not Swarm) |
deploy.resources only fully enforced in Swarm mode; use mem_limit/cpus for plain Compose |
TipThe service name in Docker Compose is also the DNS hostname other services use to reach it. Name your services after what they do (
api,postgres,redis) not after the image they use. This makes your application config readable and easy to understand.
Remember
depends_onalone only waits for a container to start, not for the application inside it to be ready. Pair it withcondition: service_healthyand a properhealthcheckblock so dependent services actually wait for readiness.
Common MistakeSetting
container_nameon services you want to scale. Docker Compose cannot create two containers with the same name — scaling a service with a fixedcontainer_namefails immediately with a naming conflict.
SecurityNever hardcode secrets directly under a service's
environmentblock in a file that gets committed to git. Useenv_filepointing to a gitignored.env, or reference a proper secret manager in production.
Frequently Asked Questions
How does a Compose service definition differ from a raw `docker run` command?
A Compose service declaratively captures everything a `docker run` command would need as flags — image, ports, environment, volumes — in version-controlled YAML, plus it names the service so other services can reference it by hostname over the automatically created Compose network. This turns a fragile sequence of manually-run docker commands into a reproducible, single-file definition of a whole multi-container application that anyone on the team can bring up identically.
What's a common mistake when defining Compose services?
Hardcoding secrets or environment-specific values (API keys, database passwords) directly into the service's `environment` block instead of using an `.env` file or Docker secrets, which then gets committed to version control. Another frequent issue is relying on `depends_on` alone to mean 'wait until ready' — by default it only waits for the container to start, not for the application inside it to be functional; pair it with a health check condition for real readiness.