Microsoft's new wslc CLI runs containers natively on Windows โ but has no Compose support yet. wslc-compose drives it from the compose.yaml you already use with Docker or Podman. No daemon, no lock-in.
$ pipx install "wslc-compose==0.5.1"
Available on PyPI โ
also
uv tool install "wslc-compose==0.5.1".
On Debian/Ubuntu (externally-managed-environment) or without pipx, use the
one-line installer.
$ cd my-project # contains the same compose.yaml as your Docker setup $ wslc compose up -d Network my-project_default created Volume my-project_data created Creating my-project-db-1 ... Creating my-project-web-1 ... $ wslc compose ps NAME SERVICE IMAGE STATUS PORTS my-project-db-1 db postgres:16 running my-project-web-1 web nginx:alpine running 0.0.0.0:8080->80/tcp $ wslc compose logs -f web $ wslc compose exec web sh $ wslc compose down -v $ wslc images # not a compose command โ forwarded verbatim to wslc.exe
Start order that follows readiness, and the first wslc 3.0.5 options.
0.5.1: one service failing to start (e.g. a host port already in use) no longer stops up — the others still start and up exits 1 with a summary.
$ wslc compose up -d Creating my-project-db-1 ... Creating my-project-migrate-1 ... Waiting for db to be healthy ... Waiting for migrate to complete ... Creating my-project-web-1 ... # web only starts once the database is ready
condition: service_healthy and service_completed_successfully. An unhealthy or crashed dependency skips only the services that need it; --wait-timeout bounds the wait.
required: false: not started when its profile is off, and a failing check only warns instead of skipping the dependent service.
restart: always, cap_add and cap_drop map to the new wslc 3.0.5 options โ detected automatically, older wslc just warns.
Validated on a live wslc session, including host.docker.internal routing; the test suite now runs on Linux and Windows.
A thin Python CLI (one dependency: PyYAML) that turns your compose file into plain wslc commands.
Finds your compose.yaml / docker-compose.yml, applies .env and ${VAR:-default} interpolation exactly like docker compose, and normalizes it.
Which networks and volumes must exist, which images to build or pull, the depends_on start order, and which containers are stale (config-hash comparison).
Plain wslc run / build / network create / ... invocations. Add --dry-run to any command to see them verbatim โ and paste them yourself if you prefer.
State lives entirely in wslc (container labels), so wslc-compose and the raw wslc CLI mix freely. When WSL ships native Compose support (microsoft/WSL#40948), migrating away is trivial โ your compose files never stopped being standard compose files.
Mapped onto the wslc preview โ including the parts that are easy to get wrong by hand.
Per-project networks; services resolve each other by name and alias, so db:5432 URLs work unchanged.
Named volumes created on demand; Linux bind-mount paths translated to the Windows paths wslc requires (wslpath -w) automatically.
build: with context, dockerfile, args, target โ images tagged <project>-<service>, rebuilt only when missing or on --build.
depends_on start order, plus condition: service_healthy and service_completed_successfully โ up waits for the database to be ready before starting the app. Optional dependencies with required: false.
up is idempotent: it recreates only the services whose resolved configuration actually changed, and leaves the rest running.
deploy.replicas, --scale svc=N, compose profiles, project scoping โ several projects coexist cleanly.
up ยท down ยท ps ยท logs -f ยท exec ยท build ยท pull ยท config โ plus a wslc wrapper so it feels exactly like docker compose.
--dry-run on any command prints every wslc invocation. Unsupported keys warn instead of failing, so existing files keep working.
healthcheck is mapped to wslc --health-* options and shown by ps as (healthy) / (unhealthy).
Overlay files with repeated -f or COMPOSE_FILE, and split big projects with include:, like docker compose.
File-backed secrets and configs are mounted read-only into containers; multiple networks with static IPs and aliases are supported too.
The sharp edges of the wslc preview โ per-elevation sessions, mount limits, wedged sessions โ documented with tested recovery steps.
A sample of the mapping โ the full table is in the README. Keys wslc can't honor yet are accepted with a warning, never a failure.
| Compose key | Handled as |
|---|---|
image, build | โ wslc run / wslc build -t project-service |
ports (short/long, ranges, udp) | โ -p |
volumes (named, bind, tmpfs, :ro) | โ -v with Windows-path translation |
networks, aliases, external | โ wslc network create, --network-alias |
environment, env_file, ${VAR} | โ full docker-compose interpolation rules |
depends_on, deploy.replicas, profiles | โ ordering, service_healthy / completed_successfully waits, scaling, opt-in services |
healthcheck | โ --health-cmd, --health-interval, โฆ |
secrets, configs (file-backed), include | โ read-only mounts, per-file path rebasing |
restart: always, cap_add, cap_drop | โ --restart, --cap-add/--cap-drop with wslc โฅ 3.0.5 |
privileged, devices, restart: unless-stopped, โฆ | โ no wslc equivalent yet โ warned, not fatal |
Already running containers with raw wslc run?
The migration guide
covers the move end to end: image retagging instead of rebuilds, port handover, verification from the
Windows loopback, rollback โ plus a recovery cheat sheet for the preview's sharp edges.