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.
$ curl -fsSL https://raw.githubusercontent.com/bacarndiaye/wslc-compose/main/install.sh | sh
$ 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
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 topological sort for start and creation order, circular dependencies rejected up front.
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.
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, scaling, opt-in services |
restart, healthcheck, privileged, โฆ | โ 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.