Using VS Code Dev Containers with wslc
The VS Code Dev Containers extension does not require Docker specifically. It requires
a binary that speaks the Docker CLI verbs, and which binary it calls is a single setting.
Point dev.containers.dockerPath at wslc and dev containers run on the
native WSL containers runtime with Docker Desktop uninstalled.
That works because the extension's core loop is just run, exec,
build, inspect and stop — all of which
wslc implements. What breaks is everything built on top of
Compose, and that is worth knowing before you migrate a working setup.
On this page
The one setting that matters
Open VS Code settings (Ctrl+,), search for Dev Containers: Docker Path,
and change it from docker to wslc. Or edit settings.json
directly:
{
"dev.containers.dockerPath": "wslc",
"dev.containers.executeInWSL": true,
"dev.containers.defaultExtensions": []
}
There is no restart required and nothing else to configure. Every container operation the extension
performs now goes through wslc.
Set this per-workspace, not globally, if you still use Docker anywhere. Putting
it in .vscode/settings.json inside the repository scopes the change to that project.
A global setting silently redirects every dev container on the machine, which is a confusing
thing to debug six weeks later on a project you forgot about.
Prerequisites
- Windows 11 with WSL on a preview build that includes
wslc. Runwsl --update --pre-releasein an elevated PowerShell, then confirm withwslc --version. The install guide covers the failure cases. - VS Code on Windows, not inside WSL.
- The WSL extension and the Dev Containers extension.
Docker Desktop can stay installed. wslc uses a separate utility VM and its own image store, so the two do not conflict — they just do not share images.
What devcontainer.json can and cannot use
Most of the spec works unchanged, because most of it maps onto plain wslc run flags.
Three things do not, and they are common enough that you will probably hit at least one:
{
"name": "app-dev",
"image": "mcr.microsoft.com/devcontainers/javascript-node:22",
// wslc understands these
"workspaceFolder": "/workspace",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
"containerEnv": { "NODE_ENV": "development" },
"forwardPorts": [3000],
"postCreateCommand": "npm install",
"remoteUser": "node"
// do NOT use with wslc:
// "dockerComposeFile" — no Compose runtime
// "features" — needs BuildKit metadata wslc build does not emit
// "runServices" — Compose-only
} | devcontainer.json key | wslc | Status | Notes |
|---|---|---|---|
image | positional image arg | Works | Any OCI image. |
build.dockerfile | wslc build | Works | args maps to --build-arg. |
build.platform | — | No | Host architecture only. |
workspaceMount | -v | VirtioFS | Forward slashes in Windows paths. |
containerEnv | -e | Works | — |
forwardPorts | -p | Works | Reachable on Windows localhost directly. |
postCreateCommand | wslc exec | Works | Also postStart / postAttach. |
remoteUser | -u | Works | — |
dockerComposeFile | — | No | No Compose runtime. See migration. |
features | — | No | Needs BuildKit metadata wslc build does not emit. |
runServices | — | No | Compose-only key. |
The features limitation is the one that surprises people, because feature blocks are
now the idiomatic way to add tooling to a dev container. Without them you bake the tooling into a
Dockerfile yourself, which is more verbose but entirely equivalent.
Where to put your project
Put it in the Linux filesystem. Clone into ~/projects/my-app, not
/mnt/c/Users/..., then open it with code . from the WSL shell.
wslc shares Windows paths over VirtioFS, which is roughly twice as fast as the 9p layer Docker
Desktop used, so the penalty is smaller than it used to be. It is not zero. Anything that touches
thousands of small files — npm install, pip install, a test suite
walking a source tree — still pays a translation cost on every operation, and that is exactly what
a dev container does on creation.
Verifying it actually worked
The failure mode to rule out is the extension silently falling back to Docker, which looks like success until you wonder why Docker Desktop started itself. Check the runtime directly:
# from the WSL shell, confirm wslc is the runtime VS Code will call
wslc --version
which wslc
# after "Reopen in Container", the dev container shows up here
wslc container list
# inspect what the extension actually created
wslc inspect <container-id>
If wslc container list shows your dev container after a successful
Reopen in Container, the extension is genuinely using wslc. If the container only
appears in docker ps, the setting did not take effect — most often because it was set
in the wrong settings scope.
Failures and what causes them
| Symptom | Cause | Fix |
|---|---|---|
docker: command not found during Reopen | Setting not applied, or applied in a scope VS Code is not reading | Confirm dev.containers.dockerPath is wslc in the active workspace |
| Reopen fails immediately on a working project | devcontainer.json uses dockerComposeFile | Replace with a single image or build; move services to manual wslc runs |
| Build fails resolving a feature | features block requires BuildKit metadata | Install the tooling in a Dockerfile instead |
Container starts, extremely slow postCreateCommand | Project lives under /mnt/c | Move it into the WSL filesystem |
| Integration tests cannot find a Docker daemon | Testcontainers needs a Docker-compatible socket; wslc exposes none | No workaround — see Testcontainers and wslc |
| Permission errors on mounted source | VirtioFS UID mapping vs remoteUser | Match remoteUser to the image's own user, or chown in postCreateCommand |
Keeping Docker for the projects that need it
If some repositories use Compose-based dev containers or Testcontainers, the pragmatic setup is
per-workspace settings: wslc in the projects that are single-container, the default
docker in the ones that are not. Docker Desktop stops launching on login and only
starts when a project actually needs it.
You give up a shared image store — each runtime pulls its own copy — in exchange for not rewriting orchestration that already works. For a machine with a handful of active projects that trade is usually worth it. The comparison guide covers the rest of what differs.
FAQ
- Can VS Code Dev Containers use wslc instead of Docker?
- Yes. Set the "Dev Containers: Docker Path" setting to wslc. The Dev Containers extension shells out to whatever binary that setting names, and wslc implements the run, exec, build, inspect and stop verbs the extension relies on. Compose-based devcontainer.json files will not work, because wslc has no Compose runtime.
- What is the Dev Containers Docker Path setting?
- dev.containers.dockerPath is the executable the Dev Containers extension invokes for all container operations. It defaults to docker. Changing it to wslc redirects every container command to the native WSL containers runtime without touching the rest of your configuration.
- Why does Reopen in Container fail with wslc?
- The three common causes are a devcontainer.json using dockerComposeFile (unsupported), a features block that needs BuildKit metadata wslc build does not emit, and a project stored under /mnt/c. Move the project into the Linux filesystem and replace the Compose config with a single image or build entry.
- Should my project live on the Windows or Linux filesystem?
- The Linux filesystem, at ~/projects rather than /mnt/c. wslc shares Windows paths over VirtioFS, which is roughly twice as fast as the old 9p layer, but native Linux storage still avoids the translation entirely. Installing dependencies is where the difference is most visible.