wslcontainers

Testcontainers and wslc

Updated 2026-07-27 · 7 min read · wslc public preview

Testcontainers does not work with wslc, and no setting will make it work. If you uninstalled Docker Desktop expecting WSL containers to cover your integration tests, that is the one workflow it cannot replace. The fix is not a wslc flag — it is running Docker Engine inside WSL2 alongside it.

This page explains the actual incompatibility, since the error messages point at the wrong thing, then gives the supported setup that keeps you off a Docker Desktop licence.

Why it cannot work

Testcontainers is a client for the Docker Engine HTTP API. On startup it runs a discovery sequence — check DOCKER_HOST, check the default Unix socket, check Docker contexts, try a /_ping request — and it needs one of those to answer. Everything it does afterwards (create container, wait for a port, stream logs, tear down via the Ryuk reaper container) is API calls against that endpoint.

wslc is daemonless. There is no dockerd, no socket, and no HTTP API. The CLI talks to a host service that starts a utility VM on demand, over a private channel that is not the Docker API and is not documented as a public interface. This is the same design decision that gives wslc near-zero idle memory use, and it is why the compatibility is not a gap someone forgot to fill.

Setting DOCKER_HOST to anything wslc-related will not help. There is no endpoint to point it at. Similarly, aliasing docker to wslc does not work: Testcontainers does not shell out to the docker binary, it opens a socket. That distinction is why VS Code Dev Containers can use wslc while Testcontainers cannot — the extension invokes a CLI, Testcontainers calls an API.

Confirming this is your problem

Typical symptoms are Could not find a valid Docker environment, DockerClientProviderStrategy failed, or a hang followed by a timeout. Verify the cause rather than guessing:

# Testcontainers looks for a Docker API. wslc provides none of these:
docker context ls                 # command does not exist in wslc
echo $DOCKER_HOST                 # empty
ls -la /var/run/docker.sock       # No such file or directory
curl --unix-socket /var/run/docker.sock http://localhost/_ping   # fails

# wslc works, but through its own private channel:
wslc container list               # fine
wslc --version                    # fine

If wslc container list succeeds while every socket probe fails, the diagnosis is confirmed: you have a working container runtime that is invisible to Testcontainers.

What else this affects

Anything that speaks the Docker API rather than the Docker CLI has the same problem. This is the broader category worth knowing before you plan a migration:

ToolTalks viawslcNotes
Testcontainers (all languages)Engine APINoJava, Go, .NET, Node, Python, Rust bindings alike.
Docker-in-Docker sidecarsMounted socketNoNothing to bind-mount.
Portainer, LazydockerEngine APINoManagement UIs cannot connect.
LocalStack (docker mode)Engine APINoSpawns containers itself.
Act (local GitHub Actions)Engine APINo
VS Code Dev ContainersCLI binaryYesSet dockerPath to wslc.
Shell scripts calling dockerCLI binaryMostlyRename verbs; see the converter.

The pattern is consistent: CLI-driven tooling ports to wslc, API-driven tooling does not. Use that as the test when evaluating anything not on this list.

The supported setup: Docker Engine in WSL2

Install Docker Engine inside an ordinary WSL2 distribution. It is open source, carries no Docker Desktop licence requirement, and gives Testcontainers exactly the API it looks for.

# Inside a normal WSL2 distro (Ubuntu), not the wslc runtime.

# 1. install Docker Engine — free, no Docker Desktop licence
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 2. enable systemd so the daemon survives shell exit
#    /etc/wsl.conf:
#      [boot]
#      systemd=true
#    then, from PowerShell: wsl --shutdown

# 3. run without sudo
sudo usermod -aG docker $USER    # log out and back in

# 4. verify Testcontainers can see a daemon
docker info
docker run --rm hello-world

After this, Testcontainers discovers the daemon with no configuration. The systemd=true step matters more than it looks — without it the daemon does not survive your shell exiting, and you get intermittent failures that look like flaky tests.

Running both side by side

wslc and Docker Engine can both be installed. They use separate utility VMs and separate image stores, so there is no conflict beyond disk usage:

TaskRuntimeWhy
Ad-hoc containers, quick serviceswslcNo daemon, near-zero idle memory, instant start
VS Code dev containerswslcExtension drives a CLI, not an API
Integration tests (Testcontainers)Docker EngineRequires the Engine API
Compose stacksDocker Enginewslc has no Compose runtime
Management UIDocker EnginePortainer needs the API

The real cost is duplicated images: a postgres:16-alpine pulled by wslc is not visible to Docker and vice versa. Budget the disk and move on.

CI is unaffected

wslc is a Windows local-development runtime. CI runners are Linux with a real Docker daemon, so nothing in your pipeline changes:

# GitHub Actions: ubuntu-latest already has a Docker daemon.
# Nothing about wslc changes CI — it is a local-development runtime.
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with: { distribution: temurin, java-version: '21' }
      - run: ./gradlew test      # Testcontainers works, daemon is present

This is worth stating because the natural worry is that dropping Docker Desktop locally will break the build. It does not. The split is only on developer machines.

FAQ

Does Testcontainers work with WSL containers (wslc)?
No. Testcontainers discovers and drives a container runtime through the Docker Engine HTTP API, usually via DOCKER_HOST. wslc is daemonless and exposes no Docker-compatible socket or API, so Testcontainers cannot detect it. There is no configuration flag that fixes this.
How do I run Testcontainers on Windows without Docker Desktop?
Install Docker Engine (docker-ce) or Podman inside a normal WSL2 distribution and point DOCKER_HOST at it. This is free, needs no Docker Desktop licence, and gives Testcontainers the Docker API it requires. wslc is not part of this path.
Why does wslc not expose a Docker socket?
It is daemonless by design. Instead of a long-running dockerd listening on a socket, the host service starts a utility VM on demand and the CLI talks to it over a private channel. That is why idle memory use is near zero, and also why socket-dependent tooling cannot attach.
Can I use wslc for development and Docker for tests?
Yes, and it is a reasonable setup. The two runtimes coexist without conflict since they use separate VMs and image stores. Use wslc for ad-hoc containers and dev containers, and Docker Engine inside WSL2 for the integration test suite. The cost is pulling images twice.

Related guides