WSL2 gives you a real Linux kernel on a Windows laptop, and for most development that is exactly what you want. Then interop bites: your project builds at a third of the speed it should, a service will not start, and localhost points at the wrong machine. Almost all of it is avoidable if you set the environment up deliberately instead of accepting the defaults.
This is the setup I hand new engineers on Windows 11: install WSL2 with Ubuntu 24.04, cap what the VM is allowed to take from the host, turn on systemd, keep code where the filesystem is fast, and understand how Linux and Windows call each other so the boundary stops surprising you. It takes about fifteen minutes and saves weeks of mysterious slowness.
Install WSL2 and Ubuntu 24.04
On a current Windows 11 build a single command in an elevated PowerShell does the whole job: it enables the required features, installs the WSL2 kernel, and pulls a distribution.
Free · 4 minutes
Is your engineering team shipping safely, or quietly accumulating risk?
Fourteen questions on how work gets from idea to production — cadence, testing, rollback, and the key-person risk in your delivery. Banded finding on screen, full sheet by email.
# Elevated PowerShell. Installs WSL2 + Ubuntu 24.04 and sets WSL2 as default.
wsl --install -d Ubuntu-24.04
# Reboot when prompted, then confirm the version.
wsl --list --verbose # VERSION column should read 2
wsl --version # WSL, kernel and WSLg build numbers
wsl --update # pull the latest kernel before you start
If wsl --list --verbose shows a distribution on version 1, convert it with wsl --set-version Ubuntu-24.04 2. Version 1 uses a translation layer rather than a real kernel; you do not want it for anything involving Docker, systemd or native filesystem behaviour.
Cap the VM with .wslconfig
Left alone, WSL2 will help itself to half your RAM and every logical processor on the machine. Those are the documented defaults: memory is 50% of host memory, processors matches the host’s logical processor count, and swap is 25% of memory rounded up to the nearest gigabyte. On a 32 GB laptop that means a 16 GB Linux VM sitting behind your IDE, browser and Teams call, and the visible symptom is the whole machine going sluggish rather than WSL itself.
This file is global, it lives in your Windows home directory, and it configures the shared WSL2 virtual machine — not any single distribution. Create C:\Users\<you>\.wslconfig:
# C:\Users\<you>\.wslconfig — configures the WSL2 VM globally
[wsl2]
memory=8GB # hard cap; leave the host enough to work with
processors=4 # logical processors handed to the VM
swap=2GB # 0 disables swap entirely
networkingMode=NAT # the default; see the interop section below
[experimental]
autoMemoryReclaim=gradual # return unused cache to Windows over time
By default WSL2 claims memory and is slow to give it back; autoMemoryReclaim lets it release cached pages to the host as pressure eases. It sits under [experimental] and the default behaviour is dropCache, so set it explicitly if you want the gradual variant. Apply changes by fully shutting the VM down — not just closing the terminal — with wsl --shutdown, then reopening the distribution.
Turn on systemd
Modern Ubuntu expects systemd as PID 1. Docker, Kubernetes tooling, snap and anything shipping a .service unit assume it is there. WSL2 supports systemd, but it is off by default and enabled per distribution in /etc/wsl.conf — a Linux-side file, not to be confused with the Windows-side .wslconfig above. Inside the distro:
# /etc/wsl.conf — per-distribution, runs inside Ubuntu
[boot]
systemd=true
[interop]
enabled=true # run Windows .exe files from Linux (default true)
appendWindowsPath=true # add the Windows PATH to Linux (default true)
Write that with sudo, run wsl --shutdown from PowerShell, reopen the distribution, and confirm with systemctl is-system-running. You want running — or degraded, which simply means one unit failed and is usually harmless on a fresh install. If you see “System has not been booted with systemd”, the file did not take; check the section headers and that you actually shut the VM down.
The 9p filesystem cliff
This is the single biggest performance mistake, and it is invisible until you measure it. WSL2 exposes your Windows drives inside Linux at /mnt/c, and it does so over a network protocol called 9p. Reads and writes across that boundary carry real per-operation overhead. A Git status, an npm install or a test run touching thousands of small files under /mnt/c can be many times slower than the same operation on the Linux filesystem — and dependency installs are exactly that pattern of many small files.
The rule is simple: keep your code inside the Linux filesystem, under ~ (which is /home/<you>), not under /mnt/c. Clone repositories there, run builds there, point your editor there.
# Do this — native ext4, fast
cd ~ && git clone git@github.com:acme/service.git
code ~/service # VS Code reattaches through the WSL server
# Not this — every file op crosses the 9p boundary
cd /mnt/c/Users/you/projects/service # slow builds, slow git
Reach across the boundary from Windows when you need to: \\wsl$\Ubuntu-24.04\home\you in Explorer, or \\wsl.localhost\Ubuntu-24.04 on newer builds, opens the Linux filesystem for the occasional file copy. Just do not work there. This filesystem discipline is also what keeps your pre-commit hooks fast enough that engineers leave them switched on.
Interop across the boundary
With interop enabled you can call Windows executables from Linux directly — explorer.exe . opens the current directory, clip.exe pipes into the Windows clipboard, and code . launches VS Code on the host attached to your Linux project. Going the other way, wsl <command> from PowerShell runs a Linux command without opening a shell.
# From Linux, invoking Windows
explorer.exe . # open current dir in Explorer
echo "copied" | clip.exe # into the Windows clipboard
# From PowerShell, invoking Linux
wsl -e bash -lc "cd ~/service && make test"
Networking is the last thing that catches people. In the default NAT mode WSL2 forwards localhost, so a dev server bound in Linux on port 3000 is reachable at http://localhost:3000 in your Windows browser without any extra work. Two caveats. First, bind your server to 0.0.0.0 rather than 127.0.0.1 if forwarding seems not to reach it. Second, if you need Windows and Linux to share one network identity — for corporate VPNs or reaching WSL services by the host’s IP — set networkingMode=mirrored in .wslconfig. It solves real problems but changes address behaviour, so switch to it because you have a specific need, not by default.
None of this is exotic. It is the difference between a WSL2 environment that behaves predictably and one that is mysteriously slow and occasionally broken — which, when a team standardises on it, is the difference between an onboarding day that ends in a green build and a week of yak-shaving. Getting the local environment right is the unglamorous foundation under every metric you later care about, from lead time and deployment frequency to whether a distributed team can actually reproduce each other’s builds. Set it up once, write the two config files into your repository’s onboarding notes, and stop paying the interop tax.
Free interactive tool
Website compliance checklist
What your site has to do, based on what it actually does
Answer as much or as little as you like — the list builds as you go. Nothing is stored against your name and no email is required.
Everything that applies
Ordered by what to do first: legal requirements you can close quickly, then larger pieces of work, then what is expected rather than required. Not exhaustive, and not a legal audit.
Dated PDF, yours to keep or circulate.
Most technology problems are not technology problems. They are control problems.
The systems exist. The investment has been made. The question is whether leadership can understand, direct, evidence, and sustain what those systems produce. Find out where control exists — and where it only appears to.