Skip to content

5. wslc or Docker Desktop?

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
  • 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).

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.11
Session started, storage in C:\Users\spare\AppData\Local\WslcHost
Image alpine:latest (8 MB)
Hello from 3.24.1 on 6.18.40.1-microsoft-standard-WSL2
Container 2b900903f6c8 exited with code 0

The 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.

  • wslc = native WSL containers, with no third-party product, still in preview.
  • Docker Desktop remains more complete (Compose, Kubernetes, GUI).
  • The Microsoft.WSL.Containers API opens up a use case Docker Desktop doesn’t cover directly: Windows applications that embed Linux containers.

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.

Terminal window
wslc volume create qdrant-data
wslc run -d --name qdrant -p 16333:6333 -v qdrant-data:/qdrant/storage qdrant/qdrant
curl.exe http://127.0.0.1:16333/
wslc container stop qdrant

Things 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.