A sidecar is a helper container that runs alongside your main application, adding capabilities without modifying the application itself. Compose has specific features to make sidecars work seamlessly.

Shared network namespace with network_mode

Use network_mode: service:<name> to share the network stack with another container, they share the same IP address and can communicate over localhost:

services:
  app:
    image: myapp
    # No ports needed — proxy handles public traffic

  proxy:
    image: nginx
    network_mode: service:app
    ports:
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro

Since both containers share the same network namespace, nginx can proxy to localhost:3000 without any DNS resolution. The app doesn’t need to know about TLS at all, the proxy sidecar handles it.

Sharing volumes with volumes_from

Use volumes_from to mount all volumes from another service, no need to declare shared named volumes manually:

services:
  app:
    image: myapp
    volumes:
      - /var/log/app
      - /app/data

  log-forwarder:
    image: fluent/fluent-bit
    volumes_from:
      - app:ro
    depends_on:
      - app

The log-forwarder gets read-only access to all of app’s volumes. This is simpler than declaring named volumes when the sidecar just needs to see everything the main container writes.

Combining both for a pod-like pattern

Use network_mode and volumes_from together to create a Kubernetes pod-like setup where containers are tightly coupled:

services:
  app:
    image: myapp
    ports:
      - "8080:8080"
    volumes:
      - /var/log/app

  log-shipper:
    image: fluent/fluent-bit
    network_mode: service:app
    volumes_from:
      - app:ro
    depends_on:
      - app

The log shipper shares the app’s network (can scrape localhost metrics endpoints) and filesystem (can read log files) — just like containers in the same Kubernetes pod.

Sidecar with depends_on and healthcheck

Ensure sidecars wait for the main service to be ready:

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready"]
      interval: 10s

  postgres-exporter:
    image: prometheuscommunity/postgres-exporter
    environment:
      DATA_SOURCE_NAME: "postgresql://postgres:${DB_PASSWORD}@postgres:5432/postgres?sslmode=disable"
    ports:
      - "9187:9187"
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  db-data:

When to use sidecars

Sidecars are a good fit when:

  • You can’t or don’t want to modify the main application image
  • The concern (logging, metrics, debugging) is orthogonal to the app
  • You want to reuse the same sidecar across multiple projects
  • You need to share network or filesystem context tightly between containers

Further reading