Skip to content

Scaling services

Run more than one replica of a compose service. SimpleDeploy shells out to docker compose up --scale and the built-in proxy round-robins requests across the replicas.

  • Stateless web tier handling more concurrent requests.
  • Background worker pool processing a queue faster.
  • Quick capacity bump during a traffic spike, scale down after.

Skip the container_name field (Compose can’t create N containers with the same name) and let the service expose a single internal port.

services:
web:
image: myapp:latest
labels:
simpledeploy.endpoints.0.domain: "myapp.example.com"
simpledeploy.endpoints.0.port: "3000"
restart: unless-stopped
worker:
image: myapp-worker:latest

App page, Overview tab, Services panel. Each scalable service shows a / count / + control. Click + to add a replica, − to remove one. Minimum is 1 (use Stop for full shutdown).

Services that can’t safely scale (databases, services with host port bindings, named volumes, or deploy.mode: global) show only the current count with a tooltip explaining why. Override detection with the simpledeploy.scalable label (below).

The proxy rebuilds its upstream pool and starts load-balancing across all replicas immediately.

A service is treated as non-scalable when any of the following hold:

  • A host port is published (ports: ["8080:8080"]).
  • A named volume is mounted (typically stateful state).
  • deploy.mode: global is set.
  • The image matches a known stateful database / broker (postgres, mysql, mariadb, mongo, redis, valkey, dragonfly, elasticsearch, opensearch, clickhouse, cassandra, rabbitmq, kafka, etcd, neo4j, influxdb, prometheus, qdrant, weaviate, minio, cockroach, …).

Override detection with a label:

services:
worker:
image: my-bespoke-stateless-pg-helper
labels:
simpledeploy.scalable: "true" # force-allow
web:
image: nginx
labels:
simpledeploy.scalable: "false" # force-block
  • No sticky sessions. Round-robin only. Store sessions in Redis or a signed cookie, not in-process memory.
  • Don’t scale stateful services. Scaling Postgres/MySQL/Redis past 1 will corrupt data. Apps that hold a file lock or bind a host port will fail to start past replica 2.
  • Host port mappings break past 1 replica. If your service has ports: ["8080:8080"], only one replica can bind. Use the expose: field plus the simpledeploy.endpoints.* labels for proxy routing instead.
  • Healthchecks recommended. Compose healthcheck: lets the proxy skip unhealthy replicas during rolling restarts.

See also: REST API, Compose labels.