5. wslc or Docker Desktop?
Comparison
Section titled “Comparison”| Criterion | wslc (WSL containers) |
Docker Desktop |
|---|---|---|
| Installation | included in WSL ≥ 2.9.3 | separate product |
| Maturity (Sept. 2026) | public preview | stable |
| CLI | close to Docker | docker |
| API for Windows applications | yes — NuGet Microsoft.WSL.Containers |
Docker Engine API (HTTP) |
| Enterprise management | Microsoft Defender for Endpoint, Intune | Docker Business |
| Ecosystem (Compose, Kubernetes, extensions, GUI) | no compose command in 2.9.11; Kubernetes, extensions, GUI to verify |
complete |
When to choose what
Section titled “When to choose what”wslc: simple needs (running a database, a service, a tool), a wish not to depend on Docker Desktop, or a Windows application that needs to drive containers.- Docker Desktop: projects based on Docker Compose, local Kubernetes, a team already tooled around Docker.
- Both: possible, but each tool keeps its own VM and its own memory. On a busy machine, that’s a real cost (see the journal).
The WSL container API
Section titled “The WSL container API”A Windows application can create its own Linux containers. The objects follow the lifecycle:
| Object | Role |
|---|---|
WslcService |
check that WSL components are installed, service version |
Session |
WSL host that manages images and creates containers |
Container |
start, stop, inspect, delete; launch processes |
Process |
read stdout/stderr, write to stdin, send signals |
The Microsoft.WSL.Containers package 2.9.9 is a C#/WinRT projection compiled against the Windows 10.0.26100 SDK, with a native DLL for x64 and arm64 only. The project must say so, otherwise the build fails with CS1705:
<PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net10.0-windows10.0.26100.0</TargetFramework> <WindowsSdkPackageVersion>10.0.26100.80</WindowsSdkPackageVersion> <RuntimeIdentifier>win-x64</RuntimeIdentifier></PropertyGroup><ItemGroup> <PackageReference Include="Microsoft.WSL.Containers" Version="2.9.9" /></ItemGroup>using System.Text;using Microsoft.WSL.Containers;
var missing = WslcService.GetMissingComponents();if (missing.Count > 0){ Console.WriteLine($"Missing WSL components: {string.Join(", ", missing)} (run wsl --install)"); return 1;}var version = WslcService.GetVersion();Console.WriteLine($"WSL container service {version.Major}.{version.Minor}.{version.Revision}");
// The session keeps its images and containers in its own storage.vhdx.var storage = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WslcHost");using var session = new Session(new SessionSettings("wslc-host", storage){ CpuCount = 2, MemorySizeInMB = 2048});session.Start();Console.WriteLine($"Session started, storage in {storage}");
await session.PullImageAsync(new PullImageOptions("docker.io/library/alpine:latest"));foreach (var image in session.GetImages()) Console.WriteLine($"Image {image.Name} ({image.Size / 1024 / 1024} MB)");
using var container = session.CreateContainer(new ContainerSettings("alpine:latest"){ Name = "wslc-host-hello", InitProcess = new ProcessSettings { CommandLine = ["/bin/sh", "-c", "echo Hello from $(cat /etc/alpine-release) on $(uname -r)"], OutputMode = ProcessOutputMode.Event }});
try{ var exited = new TaskCompletionSource<int>(); container.InitProcess.OutputReceived += data => Console.Write(Encoding.UTF8.GetString(data)); container.InitProcess.Exited += code => exited.TrySetResult(code); container.Start();
var exitCode = await exited.Task.WaitAsync(TimeSpan.FromMinutes(2)); Console.WriteLine($"Container {container.Id[..12]} exited with code {exitCode}"); return exitCode;}finally{ // Without this, a failed Start leaves the container in storage.vhdx and blocks its name. container.Delete(DeleteContainerOption.Force); session.Terminate();}WSL container service 2.9.11Session started, storage in C:\Users\spare\AppData\Local\WslcHostImage alpine:latest (8 MB)Hello from 3.24.1 on 6.18.40.1-microsoft-standard-WSL2Container 2b900903f6c8 exited with code 0The full program, which also removes a container left by a crashed run, is in code/wsl-containers/wslc-host.
Sources: WSL container — Microsoft Learn, API reference. Full samples: aka.ms/wslc-samples.
Key takeaways
Section titled “Key takeaways”wslc= native WSL containers, with no third-party product, still in preview.- Docker Desktop remains more complete (Compose, Kubernetes, GUI).
- The
Microsoft.WSL.ContainersAPI opens up a use case Docker Desktop doesn’t cover directly: Windows applications that embed Linux containers.
Exercise
Section titled “Exercise”Pick a service you currently run with Docker (for example qdrant or MongoDB) and run it with wslc. Note in the journal what differs.
Hint
If Docker already publishes qdrant on 6333, pick another Windows port: wslc would bind 6333 without any error and silently take 127.0.0.1:6333 away from the Docker container.
wslc volume create qdrant-datawslc run -d --name qdrant -p 16333:6333 -v qdrant-data:/qdrant/storage qdrant/qdrantcurl.exe http://127.0.0.1:16333/wslc container stop qdrantThings to observe: is the image downloaded again? Is it the same version as Docker’s latest? How much memory does the VM use? What does qdrant log if you mount a Windows folder instead of a volume? Answers in the journal.