Usage
Quick start
List all groups and services defined in the default compose.yaml:
$ subcompose --list
Run a named group of services:
$ subcompose run --group=core
Pipe a preview into docker compose:
$ subcompose preview --group=core | docker compose -f - up
Compose file
subcompose reads a standard Docker compose.yaml file enriched with two
custom extension fields:
x-subcompose-groupsA YAML mapping that assigns services to named groups. Each key is a group name; the value is a YAML tag referencing a service list alias.
x-subcompose-groups: core: &core - database - api full: &full - *core - frontend
x-subcompose-managedA boolean field placed on each service that declares whether the service is managed externally — that is, expected to be provided by the surrounding infrastructure rather than started by subcompose itself.
services: postgresql: image: postgres:16 x-subcompose-managed: true # provided by the platform backend: image: myapp/backend:latest x-subcompose-managed: false # always owned by us
The field has no effect on normal operation. Its only purpose is to give subcompose enough information to safely strip those services — and every
depends_onreference to them — when the--unmanagedflag is passed (see Excluding managed services (--unmanaged)).
Excluding managed services (--unmanaged)
Why managed services exist
A typical project uses two categories of service:
- Application services (
x-subcompose-managed: false) Services your team builds and owns — backends, frontends, workers. These run in Docker regardless of the environment.
- Infrastructure services (
x-subcompose-managed: true) Databases, message brokers, search engines, caches — services whose lifecycle is controlled by whoever owns the environment. On a developer’s laptop they run in Docker alongside everything else. In a shared or production environment they are provided by the platform (e.g. AWS RDS, CloudAMQP, Elasticsearch Service) and are already running before your containers start.
The x-subcompose-managed flag records this distinction so that the same
compose.yaml can serve both situations without duplication.
How it works
When --unmanaged is passed to any subcompose command:
Every service whose
x-subcompose-managedistrueis removed from the generated compose file.Any
depends_onentry that pointed to a removed service is automatically deleted from the remaining services. Entries that point to non-managed services are left intact.
Step 2 is essential: Docker Compose would refuse to start a service that declares a dependency on a service it cannot find. Subcompose removes only the managed entries so that the remaining health-check and ordering constraints continue to work correctly.
Example
Given this excerpt of a compose.yaml:
services:
postgresql:
image: postgres:16
x-subcompose-managed: true
admin:
image: myapp/admin:latest
x-subcompose-managed: false
backend:
image: myapp/backend:latest
x-subcompose-managed: false
depends_on:
admin:
condition: service_started
postgresql:
condition: service_healthy
Running subcompose preview --group=core produces a compose file that
includes all three services — suitable for local development where you want
a fully self-contained stack:
services:
postgresql:
image: postgres:16
admin:
image: myapp/admin:latest
backend:
image: myapp/backend:latest
depends_on:
admin:
condition: service_started
postgresql:
condition: service_healthy
Running subcompose preview --group=core --unmanaged produces a compose file
that contains only the application services, with the managed dependency
reference surgically removed so Docker Compose does not complain:
services:
admin:
image: myapp/admin:latest
backend:
image: myapp/backend:latest
depends_on:
admin: # kept — admin is not managed
condition: service_started
# postgresql entry removed automatically
Notice that backend’s dependency on admin is preserved — only the
reference to the managed postgresql service is stripped.
Environment scenarios
Environment |
Command |
What starts in Docker |
|---|---|---|
Local development |
|
All services, including managed ones (databases, brokers, …) |
CI / shared infrastructure |
|
Application services only; connects to the shared database and broker already running in the environment |
Production |
|
Application services only; managed services are platform-provided (AWS RDS, CloudAMQP, Elastic Cloud, …) |
Tip
When deploying to a shared environment, application services connect to
the managed infrastructure using environment variables
(DATABASE_URL, RABBITMQ_SERVER_URL, etc.). Subcompose removes
the managed containers from the compose file but leaves those environment
variable references untouched, so the application still finds the
externally-provided services at the correct host and port.
Default value
If a service does not declare x-subcompose-managed at all, subcompose
treats it as not managed (equivalent to x-subcompose-managed: false).
The field only needs to be set to true for infrastructure services that
should be suppressible with --unmanaged.
Groups and services
Select services by group
$ subcompose run --group=core
Multiple groups and individual services can be combined:
$ subcompose run --group=core --group=elk --service=kibana
Variable interpolation
Enable shell-style variable substitution with --interpolate:
$ subcompose preview --group=core --interpolate
Validation
Check the compose file for group and volume consistency:
$ subcompose validate
Automatically fix detected issues:
$ subcompose validate --fix