Skip to main content

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.

graph LR A[payment-api service] -->|DB_HOST env var| B[postgres service] A -->|CACHE_HOST env var| C[redis service] B --> D[postgres-data volume]

A Complete Service Definition

YAML
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

YAML
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 active

Service Scaling

Bash
# Scale a service to 3 instances
docker 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 running
docker compose ps
# NAME STATUS
# project-api-1 Up
# project-api-2 Up
# project-api-3 Up

Service Discovery Between Services

Every service name in Compose is automatically a DNS hostname reachable by every other service on the same project network:

Bash
# Verify from inside one running service
docker compose exec payment-api ping postgres
# PING postgres (172.20.0.3) — resolves automatically

Quick 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
Tip

The 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_on alone only waits for a container to start, not for the application inside it to be ready. Pair it with condition: service_healthy and a proper healthcheck block so dependent services actually wait for readiness.

Common Mistake

Setting container_name on services you want to scale. Docker Compose cannot create two containers with the same name — scaling a service with a fixed container_name fails immediately with a naming conflict.

Security

Never hardcode secrets directly under a service's environment block in a file that gets committed to git. Use env_file pointing 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.