Docker Compose — Defining Services
A service is a container definition in your compose file. This page covers all the common options you’ll use when defining services.
Basic Service Definition
services:
web: # Service name (you choose this)
image: nginx:alpine # Docker image
container_name: my-nginx # Custom container name
ports:
- "80:80" # Port mapping
environment:
NGINX_HOST: example.com # Environment variable
volumes:
- ./html:/usr/share/nginx/html # Volume mount
restart: unless-stopped # Restart policy
labels:
app: web # Container labels
env: production
Service Options Reference
image
Specifies which Docker image to use:
services:
# Full image reference
db:
image: postgres:16-alpine
# Docker Hub official image
cache:
image: redis:7
# Custom registry
api:
image: registry.example.com/myapp:v1.2.3
container_name
Override the default container name:
services:
db:
image: postgres:16
container_name: my-database
Default name: <project>-<service>-<number> (e.g., myapp-db-1)
Warning: Custom container names prevent scaling — you can’t have two containers with the same name. Only use this when you need a specific name.
restart
Defines when Docker should restart the container:
services:
web:
image: nginx
restart: unless-stopped
| Policy | Behavior |
|---|---|
no |
Never restart (default) |
always |
Always restart, even after manual stop |
on-failure |
Restart only on non-zero exit code |
unless-stopped |
Always restart except after manual docker stop |
For development: use no or on-failure
For production: use unless-stopped
environment
Set environment variables for the container:
services:
db:
image: postgres:16
environment:
# Map syntax (recommended)
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
POSTGRES_DB: myapp
Or list syntax:
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=myapp
labels
Add metadata labels to containers:
services:
web:
image: nginx
labels:
com.example.app: "web"
com.example.env: "production"
com.example.team: "platform"
Labels are useful for monitoring tools, reverse proxies (Traefik), and container management.
A Complete Multi-Service Example
services:
frontend:
image: nginx:alpine
container_name: blog-frontend
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
restart: unless-stopped
labels:
app: blog
tier: frontend
backend:
image: node:20-alpine
ports:
- "3000:3000"
environment:
NODE_ENV: production
DB_HOST: database
restart: unless-stopped
labels:
app: blog
tier: backend
database:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: blog
volumes:
- db-data:/var/lib/postgresql/data
restart: unless-stopped
labels:
app: blog
tier: data
volumes:
db-data:
Summary
| Option | Purpose | Example |
|---|---|---|
image: |
Docker image to use | postgres:16 |
container_name: |
Custom name (prevents scaling) | my-db |
ports: |
Port mapping | "80:80" |
environment: |
Environment variables | POSTGRES_PASSWORD: secret |
volumes: |
Data mounts | db-data:/var/lib/postgresql/data |
restart: |
Restart policy | unless-stopped |
labels: |
Metadata | app: web |
Quick Reference
| Item | Detail |
|---|---|
| Service name | You choose — becomes DNS hostname |
| image | Docker image to pull and run |
| container_name | Custom name — prevents scaling |
| restart | unless-stopped for production |
| environment | Key-value env vars for container |
| labels | Metadata for tooling and management |