Decision. Spend 3–6 months in WSL2 to retire the userland risk — bash, coreutils, apt, git, Docker,
dotnet/bunon Linux — because that part is genuinely identical, and WSL2 now runs a real Microsoft-built Linux 6.18 kernel with systemd[1][2][3]. Then stop: WSL2 cannot teach you a display server, a bootloader, drivers, suspend/resume, or package-manager-owns-the-machine, and it hides the single decision that dominates day-one pain — your repos must live on ext4, not/mnt/c, which is exactly where a Dropbox-synced Windows folder puts them[4][5].
What WSL2 genuinely validates
These transfer 1:1 to bare metal. If they work here, they work there.
| Capability | 2026 status in WSL2 | Source |
|---|---|---|
| Real Linux kernel + full syscall compat | Microsoft-built kernel, current branch linux-msft-wsl-6.18.y, serviced by Windows Update |
[1] [2] |
| bash / coreutils / apt / man pages | Unmodified distro userland | [1] |
| systemd | ✓ since WSL 0.67.6; [boot] systemd=true in /etc/wsl.conf, then wsl --shutdown |
[6] [3] |
| Docker / containers | ✓ full syscall compat; native wslc container runtime in public preview since 29 Jun 2026 (WSL 2.9.3), GA targeted autumn 2026 |
[1] [7] |
dotnet CLI + debugging on Linux |
✓ Visual Studio ships a WSL launch profile; the runtime is the real linux-x64 runtime | [8] |
| GPU compute (CUDA) | ✓ via GPU-PV and /dev/dxg; nvidia-smi works with only the Windows driver installed |
[9] [10] |
| Linux GUI apps (WSLg) | ✓ Wayland + XWayland, Weston with an RDP backend, PulseAudio in/out, GPU accel via Mesa d3d12 | [11] |
| Raw CPU/IO ceiling | Phoronix (15 Sep 2025, Ryzen 9 9950X3D, Ubuntu 24.04 vs bare metal): ~10–15% CPU overhead, up to ~20% on I/O | [12] [13] |
WSL itself went open source at Build 2025 (MIT), so the seams are now inspectable: wsl.exe, wslservice.exe, the Linux-side init/gns/localhost daemons and the plan9 server[14][15] — microsoft/WSL ⭐ 33k (Jul 2026)[16]. Still closed: lxcore.sys (WSL1) and p9rdr.sys/p9np.dll, the \\wsl.localhost redirector[15].
The filesystem cliff — the number that decides your setup
Microsoft’s own guidance: “We recommend against working across operating systems with your files… store your files in the WSL file system if you are working in a Linux command line”[4]. The mechanism is a plan9 file server in wslservice.exe reached over a Hyper-V socket, one round-trip per operation[17].
| Operation | WSL ext4 (VHDX) | WSL → /mnt/c |
Windows → \\wsl$ |
|---|---|---|---|
| Sequential read 1 MB | 2393 MB/s | 86 MB/s | 156 MB/s |
| Sequential write 100 MB | 2827 MB/s | 294 MB/s | 10 MB/s |
| Random read | 24 554 IOPS | 725 IOPS | 1271 IOPS |
| Directory traversal | 343 338 files/s | 13 561 files/s | 28 045 files/s |
Source: wsl-filesystem-benchmark ⭐ 3 (Jul 2026)[5]. Random read across the boundary is ~34× slower; Windows→WSL writes land under 1% of native. The canonical bug, microsoft/WSL#4197, reports 40.4 MB/s on /mnt under WSL2 vs 442 MB/s under WSL1 and is still open[18].
⚠ 2026 change: virtiofs is now selectable (virtiofs=true under [wsl2], kernel 6.18.26.3-1+), replacing plan9 for /mnt/*; a 27 May 2026 PR gave each virtio device its own DMA pool to remove the last SWIOTLB contention point. It is still opt-in — plan9 remains the default[19][17]. HN reports a Hugo build at 50 s on native ext4, 75 s on virtiofs, and “3–5 m or more” on plan9 — virtiofs closes most of the gap but does not close it[20].
The Dropbox trap. A repo under C:\Users\you\Dropbox\... is doubly penalised: every git status, dotnet build and node_modules walk pays the cross-OS tax above, and the sync client indexes tens of thousands of dependency files it cannot exclude per-directory[21]. The fix is not tuning — it is git clone into ~/code and letting the remote be the sync mechanism. This is a rehearsal for bare metal, where /mnt/c does not exist at all.
What WSL2 structurally hides
Every row here is a real migration risk that WSL2 cannot retire.
| Hidden layer | What WSL2 substitutes | Why it doesn’t count |
|---|---|---|
| Display server | WSLg: Weston + RDP remoting individual windows onto the Windows desktop | You never pick Wayland vs X11, never configure a compositor, never hit fractional-scaling or multi-monitor bugs. Running a real DE needs an XRDP hack; GNOME Shell needs 3D accel XRDP can’t give, and KDE Plasma 6.8 is Wayland-only[22][23] |
| GPU drivers | /dev/dxg + stub libcuda.so/nvidia-smi in /usr/lib/wsl/lib, forwarding to the Windows driver |
Installing a real Linux GPU driver breaks it. You never do DKMS, kernel-module signing, or a Nouveau→proprietary switch[10] |
| Kernel ownership | Microsoft-built kernel, serviced by Windows Update | No apt-owned kernel, no headers/module rebuild, no bad-kernel rollback[1] |
| Bootloader / firmware | none — VM boot | No GRUB, no Secure Boot, no UEFI, no “it doesn’t boot” recovery drill |
| Suspend / resume | none — Windows sleeps, the VM doesn’t notice | Surfaces only as clock skew: “the VM for the WSL Linux distro doesn’t have its clock updated when the host resumes” — fix is sudo hwclock -s[24] |
| Battery / thermal / power mgmt | Windows owns all of it | TLP, powertop, CPU governors, lid actions: untested |
| Peripherals | USB only via usbipd-win ⭐ 6.0k (Jul 2026), attach-by-busid, exclusive to WSL while attached; serial ports unsupported | No udev-rules-for-a-real-device, no printer/scanner/webcam/fingerprint reality check[25][26][1] |
| Networking | NAT by default: WSL2 gets its own virtual adapter and a unique IP that changes on restart; LAN exposure needs netsh portproxy. mirrored mode fixes most of it but IPv6 ::1 is unsupported and it silently falls back to NAT on Windows builds lacking the feature |
You never touch NetworkManager/systemd-networkd, nmcli, or Wi-Fi/VPN driver reality[27][28] |
| Init / service ownership | systemd runs, but inside a distro cgroup managed by WSL | snapd still doesn’t work[29]; systemd ≥ 256 needed plain cgroup v2 support that WSL’s hybrid hierarchy lacked[30] |
2026 sharp edges worth knowing before you start
- Memory ballooning. The Linux page cache grows and Windows can’t see it as reclaimable — Microsoft’s own example shows 2 GB attributed to the VM in Windows while Linux is using 50 MB[31].
autoMemoryReclaimnow defaults todropCache(was previously off);gradualis the gentler option[3]. - VHDX only grows. Default max is 1 TB and deleting files does not shrink the file. Enable
sparseVhd=true(orwsl --manage <distro> --set-sparse true) — ⚠ once sparse,Optimize-VHDrefuses to compact it, so you’re committed to automatic reclaim[3][32][33]. - inotify does not cross the boundary. File-watching on
/mnt/cdoesn’t fire, so Vite/Angular/dotnet watchHMR silently dies; the workaround is polling — or, correctly, moving the repo to ext4[34]. - Case sensitivity is inverted per-tree. Windows drives mount case-insensitive by default (
case=off); ext4 is case-sensitive. Mixed-case files created in WSL become unopenable from Windows tools, andgit config core.ignorecasedisagreements produce phantom conflicts[35]. - cgroup v1 is gone. WSL now isolates each distro’s systemd into its own cgroup v2 hierarchy;
IsolateDistroCgroup(defaulttrue) is the escape hatch for legacy v1 workloads[36][37]. - The 8-second rule. Config edits need the VM fully stopped (
wsl --shutdown), not just the terminal closed[3].
A sane %UserProfile%\.wslconfig baseline for a 32 GB dev box:
[wsl2]
memory=16GB
processors=8
networkingMode=mirrored
virtiofs=true
[experimental]
autoMemoryReclaim=gradual
sparseVhd=true
hostAddressLoopback=true
hostAddressLoopback and ignoredPorts only apply under mirrored[3]; virtiofs needs kernel 6.18.26.3-1+[19].
Verdict: which risks WSL2 retires
| Migration risk | Retired by WSL2? |
|---|---|
| “Will my .NET/TS toolchain build and debug on Linux?” | ✓ |
| “Can I live in bash instead of PowerShell?” | ✓ |
| “Do my Docker/compose/homelab deploy scripts work?” | ✓ |
| “Will my ML/CUDA work run?” | ✓ (compute only) |
| “Can I package-manage my own machine?” | ✗ |
| “Will my laptop suspend, wake, and hold charge?” | ✗ |
| “Will my GPU/Wi-Fi/fingerprint/dock work?” | ✗ |
| “Which DE/compositor do I actually want?” | ✗ |
| “Can I recover an unbootable system?” | ✗ |
Stop learning from WSL2 when your friction stops being “how do I do X in Linux” and becomes “I want Linux to be the machine” — the point where WSL2 mistakes are still trivially unwound but the questions it can answer have run out[38]. Concretely: when you have (a) all repos on ext4 with no /mnt/c dependency, (b) systemd units you wrote yourself, and (c) a dotfiles repo you can git clone onto a fresh box. At that point the next rung is a machine WSL2 can’t simulate — and everything remaining on the ✗ list has to be learned on real hardware.