Prevent containers from consuming all available resources. Set CPU and memory limits to ensure stable multi-service deployments.

The basics

Resource limits protect your system from runaway containers:

services:
  api:
    image: node:20
    deploy:
      resources:
        limits:
          cpus: '0.5'     # Half a CPU core
          memory: 512M    # 512 megabytes
        reservations:
          cpus: '0.25'    # Minimum guaranteed
          memory: 256M

The container can use up to 512MB memory and 50% of one CPU core.

Real-world example

Production stack with proper resource allocation:

services:
  nginx:
    image: nginx:alpine
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
        reservations:
          memory: 128M

  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '2.0'     # 2 full cores
          memory: 2G
        reservations:
          cpus: '1.0'
          memory: 1G

  postgres:
    image: postgres:15
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        reservations:
          memory: 512M

Monitor resource usage

Check actual resource consumption:

# Real-time resource usage for all services
docker compose stats

# Monitor specific service
docker compose stats app

# One-time snapshot
docker compose stats --no-stream

Output shows:

NAME     CPU %   MEM USAGE / LIMIT   MEM %
app      45.2%   892MiB / 2GiB       43.5%
nginx    0.1%    12MiB / 256MiB      4.7%
postgres 12.3%   467MiB / 1GiB       45.6%

Development vs production

Use environment variables for different environments:

services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '${CPU_LIMIT:-2.0}'
          memory: '${MEMORY_LIMIT:-2G}'
# Development (relaxed limits)
CPU_LIMIT=4.0 MEMORY_LIMIT=4G docker compose up

# Production (strict limits)
CPU_LIMIT=1.0 MEMORY_LIMIT=1G docker compose up

Common issues

Container killed (exit code 137):

# Out of memory - increase limit
deploy:
  resources:
    limits:
      memory: 1G  # Was 512M

Slow performance:

# CPU throttling - increase CPU limit
deploy:
  resources:
    limits:
      cpus: '2.0'  # Was 0.5

Pro tip

Test your limits under load before production:

# Stress test with limited resources
docker compose up -d
docker exec app stress --cpu 4 --vm 2 --vm-bytes 256M --timeout 30s

# Check if limits hold
docker compose stats --no-stream

This ensures your limits are realistic for actual workload.

Further reading