WSL — Linux on Windows Developer Guide
What is WSL?
WSL2 = Linux kernel in a managed VM; keep repos on the Linux fs, drive it with wsl.exe + interop.
Install with `wsl --install` (admin PowerShell) → Ubuntu on WSL 2 by default. Manage with `wsl -l -v`, `--set-version`, `--shutdown`, `--export/--import`. Tune the VM globally in `%UserProfile%\.wslconfig` ([wsl2] memory/processors/networkingMode=mirrored) and per-distro in `/etc/wsl.conf` ([boot] systemd=true). The rule that governs everything: store code in `/home/you/code`, never `/mnt/c` — cross-OS I/O is the one thing WSL1 beats WSL2 at, and on the Linux fs WSL2 is up to 20× faster unpacking tarballs, 2–5× on git/npm/cmake. It's the right place to run Claude Code on Windows: native Linux toolchain, Windows interop one `explorer.exe .` away.
Six things to know
The architecture, the golden rule, and the tooling it unlocks. Tap a card for commands + gotchas.
Where should your code live? — the filesystem advisor
WSL’s single biggest gotcha. Choose where your files live and which OS’s tools touch them — watch the path translation and the speed verdict flip. The lesson in one move: drag “files” to Windows while using Linux tools and watch it fall off the performance cliff.
The rule (store files on the filesystem matching your tools) and the 2–20× range are from Microsoft Learn (compare-versions, filesystems). The speed bar is relative/illustrative — actual gains depend on the workload. Apply it: keep repos in ~/codeand run Claude Code from there.
██╗ ██╗███████╗██╗
██║ ██║██╔════╝██║
██║ █╗ ██║███████╗██║
██║███╗██║╚════██║██║
╚███╔███╔╝███████║███████╗
╚══╝╚══╝ ╚══════╝╚══════╝WSL — Linux on Windows Developer Guide
Focus: Everything a developer needs to run Linux on Windows with WSL — install, architecture, distro management, the filesystem performance rule, the full command + config reference, systemd, Docker/GPU/USB/GUI, Windows Terminal, VS Code, and running Claude Code inside WSL. Grounded in
learn.microsoft.com; reviewed 2026-06-07.
Good news: getting a real Linux environment on Windows is now a one-command affair, and once you internalise a single rule (keep your code on the Linux side), it's genuinely fast and pleasant. Work through the diagrams below, copy the commands as you go, and you'll have a production-grade dev box in an afternoon. Let's dive in.
Table of Contents
- Overview & architecture
- Install & first run
- WSL 1 vs WSL 2
- Distribution management
- The filesystem: interop & the performance rule
- Command reference
- Configuration:
.wslconfigvswsl.conf - systemd & Linux services
- Interop: running Windows ↔ Linux
- Networking & ports
- Docker, GPU, USB & GUI apps
- Windows Terminal & shell setup
- VS Code in WSL
- Claude Code in WSL
- Automations & dotfiles
- Troubleshooting
- codeAmani notes
The interactive learn module above this page is a live filesystem-location advisor + WSL1/WSL2 explorer — start there for intuition, then use this reference.
Official Documentation
| Resource | URL |
|---|---|
| WSL docs (root) | https://learn.microsoft.com/windows/wsl/ |
| Install WSL | https://learn.microsoft.com/windows/wsl/install |
| Basic commands | https://learn.microsoft.com/windows/wsl/basic-commands |
| Comparing WSL 1 & 2 | https://learn.microsoft.com/windows/wsl/compare-versions |
| Working across filesystems | https://learn.microsoft.com/windows/wsl/filesystems |
| Advanced settings (config) | https://learn.microsoft.com/windows/wsl/wsl-config |
| systemd support | https://learn.microsoft.com/windows/wsl/systemd |
| Set up a dev environment | https://learn.microsoft.com/windows/wsl/setup/environment |
1. Overview & architecture
The Windows Subsystem for Linux lets you run an unmodified Linux distribution (Ubuntu, Debian, Kali, openSUSE, Arch, …) directly on Windows — Linux apps, utilities, and Bash — without a traditional VM or dual-boot.
WSL 2 (the default) runs a genuine Linux kernel inside a lightweight utility VM, giving 100% system-call compatibility, systemd, Docker, and GPU compute. Each distro is an isolated container inside that managed VM. Here's the whole picture in one diagram — notice the two filesystems, because that distinction decides your performance:
Prerequisites: Windows 11, or Windows 10 version 2004 / build 19041+ (WSL 2 needs Win 10 1903 / build 18362+).
2. Install & first run
Open PowerShell as Administrator and run one command:
wsl --installThat single command does a surprising amount of work for you — here's the whole flow, start to finish:
This enables the WSL + Virtual Machine Platform components, downloads the latest Linux kernel, sets WSL 2 as default, and installs Ubuntu. Reboot when prompted. On first launch you create a Linux username + password (separate from Windows).
# Install a specific distro instead of Ubuntu
wsl --list --online # see available distros
wsl --install -d Debian
wsl --install -d Ubuntu-24.04 --no-launch
# Keep WSL itself up to date
wsl --update
wsl --version # confirm kernel / WSL versionIf
wsl --installonly prints the help text, WSL is already present — usewsl --install -d <Distro>. If a download hangs at 0.0%, add--web-download.
3. WSL 1 vs WSL 2
WSL 2 is the recommended default. The official feature comparison:
| Feature | WSL 1 | WSL 2 |
|---|---|---|
| Windows ↔ Linux integration | ✅ | ✅ |
| Fast boot, small footprint | ✅ | ✅ |
| Managed VM | ❌ | ✅ |
| Full Linux kernel | ❌ | ✅ |
| Full system-call compatibility | ❌ | ✅ |
| Performance across OS file systems | ✅ | ❌ |
| systemd support | ❌ | ✅ |
| Runs alongside VMware/VirtualBox | ✅ | ❌ |
| IPv6 | ✅ | ✅ |
Read the table this way: WSL 2 wins everywhere except cross-OS file access — and you neutralise that by keeping files on the matching filesystem (§5). WSL 2 runs up to 20× faster unpacking a tarball and 2–5× faster on git clone / npm install / cmake than WSL 1 — when files live on the Linux side.
Pick WSL 1 only if: files must live on the Windows filesystem and you access them from Linux tools; you need a serial port; or you have strict host-memory limits.
wsl -l -v # which version is each distro on?
wsl --set-version Ubuntu 2 # upgrade a distro to WSL 2
wsl --set-default-version 2 # default for new installs4. Distribution management
wsl -l -v # list installed distros + version + state
wsl --set-default Ubuntu # set the default distro
wsl -d Debian # launch a specific distro
# Backup / clone / move a distro (export → import)
wsl --export Ubuntu D:\backups\ubuntu.tar # snapshot to tar (--vhd for .vhdx)
wsl --import UbuntuClone D:\wsl\clone D:\backups\ubuntu.tar
wsl --unregister UbuntuClone # delete a distro + its disk (irreversible)
# Per-distro default user (launcher distros)
ubuntu config --default-user johndoe
--export/--importis your portable backup and the way to move a distro off the system drive.--unregisterpermanently deletes the distro's ext4 VHDX — back up first.
5. The filesystem: interop & the performance rule
The single most important WSL habit. Get this one right and everything feels fast; get it wrong and you'll blame WSL for being slow when it's really the boundary crossing. Each filesystem is fast from its own OS and slow across the boundary:
| Where the files are | Path from Linux | Path from Windows | Fast for |
|---|---|---|---|
| Linux filesystem (ext4 VHDX) | /home/you/code | \\wsl$\Ubuntu\home\you\code | Linux tools ✅ |
| Windows filesystem | /mnt/c/Users/you/code | C:\Users\you\code | Windows tools ✅ |
✅ Keep your repos in the Linux filesystem (
/home/you/...) when you work with Linux tooling (git, npm, build chains). Putting them on/mnt/cforces every file op across the OS boundary and is dramatically slower.
# Jump between worlds
explorer.exe . # open the current Linux dir in File Explorer
cd /mnt/c/Users/you/Downloads # reach the Windows C: drive from Linux
# In Windows File Explorer address bar: \\wsl$ or \\wsl.localhost# Clone into the Linux fs (fast), NOT /mnt/c (slow)
mkdir -p ~/code && cd ~/code
git clone https://github.com/codeAmani-Solutions/your-repo.git6. Command reference
All from PowerShell/CMD (use wsl.exe from inside Linux):
| Command | Does |
|---|---|
wsl --install [-d <Distro>] | Install WSL + a distro |
wsl --list --online | List installable distros |
wsl -l -v | List installed distros, version, state |
wsl --set-version <Distro> <1|2> | Convert a distro's WSL version |
wsl --set-default-version 2 | Default version for new distros |
wsl -d <Distro> | Launch a specific distro |
wsl --update / wsl --version | Update / show WSL version |
wsl --shutdown | Stop the WSL 2 VM + all distros (apply .wslconfig) |
wsl --terminate <Distro> | Stop one distro |
wsl --export <Distro> <file> | Snapshot a distro (--vhd for .vhdx) |
wsl --import <Name> <dir> <file> | Restore/clone a distro |
wsl --unregister <Distro> | Delete a distro + its disk |
wsl hostname -I | WSL 2 VM IP address |
wsl --status | Default distro/version + kernel info |
7. Configuration: .wslconfig vs wsl.conf
Two files, two scopes:
| Aspect | .wslconfig | wsl.conf |
|---|---|---|
| Scope | Global — the WSL 2 VM, all distros | Per-distro |
| Location | %UserProfile%\.wslconfig (Windows) | /etc/wsl.conf (inside the distro) |
| Configures | RAM, CPUs, swap, networking, kernel | boot/systemd, automount, interop, default user |
# %UserProfile%\.wslconfig — global WSL 2 VM tuning
[wsl2]
memory=8GB # cap VM RAM (default: 50% of host)
processors=4 # logical CPUs (default: all)
swap=2GB
localhostForwarding=true
guiApplications=true # WSLg
networkingMode=mirrored # better VPN/IPv6 compatibility
dnsTunneling=true
autoMemoryReclaim=gradual# /etc/wsl.conf — per-distro settings
[boot]
systemd=true
[automount]
enabled=true
options="metadata,umask=22,fmask=11" # sane perms on /mnt/c files
root=/mnt/
[interop]
enabled=true # run Windows .exe from Linux
appendWindowsPath=true # add Windows PATH to the Linux PATH
[user]
default=johndoeApply
.wslconfigchanges withwsl --shutdown(then relaunch).wsl.confchanges apply on the next distro start.
8. systemd & Linux services
systemd is the default on current Ubuntu via wsl --install. To enable it on any WSL 2 distro (requires WSL 0.67.6+):
sudo nano /etc/wsl.conf[boot]
systemd=truewsl --shutdown # from Windows, then relaunch the distrosystemctl status # verify systemd is PID 1
sudo systemctl enable --now postgresql # manage real services
systemctl list-unit-files --type=service9. Interop: running Windows ↔ Linux
# Run Windows programs from Linux (note the .exe)
explorer.exe . # open current dir in File Explorer
code . # launch VS Code connected to WSL
clip.exe < file.txt # copy file contents to the Windows clipboard
powershell.exe -c "Get-Date"
notepad.exe config.json
# Pipe across the boundary
cat report.csv | clip.exe
ls | findstr.exe ".log" # Linux output → Windows tool# Run Linux commands from Windows
wsl ls -la ~
wsl --cd ~ -- bash -lc "npm run build"
wsl grep -r "TODO" .Interop is toggled per-distro in
wsl.conf([interop] enabled,appendWindowsPath).
10. Networking & ports
WSL 2's default NAT mode forwards localhost between Windows and Linux, so a dev server on :3000 in Linux is reachable at http://localhost:3000 in your Windows browser.
# Start a server in WSL — open it in the Windows browser at localhost:3000
npm run dev # Next.js / Vite, etc.
wsl hostname -I # the WSL 2 VM IP if you need it directly# %UserProfile%\.wslconfig — mirrored mode for VPNs / IPv6 / better localhost
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true # inherit Windows HTTP proxyFrom Windows 11 22H2 + WSL 2.0.9+, Windows Firewall rules apply to WSL automatically (Hyper-V firewall).
11. Docker, GPU, USB & GUI apps
- Docker — install Docker Desktop and enable the WSL 2 backend; the
dockerCLI then works inside every WSL distro with near-native performance (WSL 2's real kernel is what makes this possible). - GPU compute — WSL 2 supports GPU paravirtualization (NVIDIA CUDA, DirectML) for ML/AI workloads; install the vendor's WSL driver on Windows.
- USB devices — not native; attach them with the
usbipd-winproject (usbipd attach --wsl). - GUI apps (WSLg) — Linux GUI apps run out of the box (
guiApplications=true); justsudo apt installand launch.
docker run --rm hello-world # via Docker Desktop's WSL2 backend
nvidia-smi # confirm GPU passthrough (with the driver)12. Windows Terminal & shell setup
Windows Terminal auto-detects WSL distros as profiles (tabs, splits, themes). Set your distro as the default profile for a one-keystroke Linux shell.
# A typical first-hour setup inside the distro
sudo apt update && sudo apt upgrade -y
sudo apt install -y git curl build-essential zsh unzip
chsh -s $(which zsh) # optional: switch to zsh
git config --global user.name "Your Name"
git config --global user.email "you@codeamani.com"Use Git Credential Manager on Windows so Linux git reuses your Windows credentials (
git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe").
13. VS Code in WSL
Install the WSL extension on Windows, then from a WSL shell:
cd ~/code/your-repo
code . # opens VS Code as a client; the server runs inside WSLThe extensions, terminal, debugger, and language servers all execute in Linux against your Linux-filesystem files — full speed, no /mnt/c penalty.
14. Claude Code in WSL
WSL is an excellent home for Claude Code on a Windows machine: a native Linux toolchain (the environment most CLIs assume) with Windows interop a command away.
# Inside your WSL distro
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
npm install -g @anthropic-ai/claude-code # see the claude-api guide for current install
cd ~/code/your-repo # keep the repo on the LINUX fs for speed
claude # launch in the projectWhy it clicks:
- Toolchain parity — Bash, the GNU coreutils, and POSIX paths Claude Code's commands expect are all native.
- Speed — with the repo in
/home, file watching,git, andnpmrun at full speed (the §5 rule). - Interop for verification — Claude can
explorer.exe .to show you a folder, or drive Windows tools, while staying in Linux. Pair with the chrome-devtools MCP to verify UIs in a real browser.
Run
wsl --updateperiodically so the kernel + WSL features stay current for whatever you're building.
15. Automations & dotfiles
# ~/.bashrc — quality-of-life helpers
alias e='explorer.exe .'
alias winhome='cd /mnt/c/Users/$USER'
alias dev='cd ~/code'
export BROWSER='/mnt/c/Program Files/Google/Chrome/Application/chrome.exe'
# One-shot dev-box bootstrap (idempotent) — drop in ~/bootstrap.sh
#!/usr/bin/env bash
set -euo pipefail
sudo apt-get update -y
sudo apt-get install -y git curl build-essential jq
command -v node >/dev/null || { curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -; sudo apt-get install -y nodejs; }
echo "✅ dev box ready"# Windows-side: a scheduled nightly WSL backup (Task Scheduler / PowerShell)
wsl --export Ubuntu "D:\backups\ubuntu-$(Get-Date -Format yyyyMMdd).tar"// .claude/settings.json — nudge keeping repos off /mnt/c
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command",
"command": "case \"$PWD\" in /mnt/c/*) echo 'You are under /mnt/c — Linux-fs (~/) is much faster for git/npm';; esac" }] }
]
}
}16. Troubleshooting
| Issue | Fix |
|---|---|
wsl --install only prints help | WSL already installed — use wsl --install -d <Distro> |
| Install hangs at 0.0% | wsl --install --web-download -d <Distro> |
| Everything feels slow | Repo is on /mnt/c — move it to ~/ (the Linux fs) |
.wslconfig change ignored | Run wsl --shutdown, then relaunch |
| systemd not running | Add [boot] systemd=true to /etc/wsl.conf, wsl --shutdown; needs WSL 0.67.6+ |
localhost:3000 unreachable from Windows | Confirm the server binds 0.0.0.0/localhost; try networkingMode=mirrored |
| VM eating RAM | Cap it: [wsl2] memory=8GB + autoMemoryReclaim=gradual |
| VPN breaks WSL networking | [wsl2] networkingMode=mirrored + dnsTunneling=true |
| Can't access GPU/USB | Install the vendor WSL driver; for USB use usbipd-win |
| Distro corrupted | Recover with [wsl2] safeMode=true, or restore from wsl --export backup |
17. codeAmani notes
- The performance rule is non-negotiable. Keep every repo in the Linux filesystem (
~/code/...), never/mnt/c. On the I/O-heavy work we do daily —git,npm install, Next.js builds — that's the 2–20× difference Microsoft documents. The.claudehook in §15 nags you if you stray onto/mnt/c. - Run Claude Code inside WSL. It gives the Linux toolchain our stack assumes (Bash, POSIX paths, native node tooling) while keeping Windows interop one
explorer.exe .away. See claude-api for the current CLI install. - Secrets stay server-side. WSL doesn't change the rules — keep Daraja/M-Pesa keys and tokens in
.env.local(Linux side, git-ignored) or a secret manager, never in shell history or committed dotfiles. Use Git Credential Manager so you're not pasting PATs into the Linux shell. - Cap resources on modest hardware. Many East-African dev machines are RAM-light; set
[wsl2] memory=+autoMemoryReclaim=gradualso the WSL VM doesn't starve Windows. - Mirror your prod target. Our services run on Linux (Cloud Run, containers). Developing in WSL means dev/prod parity — the same shell, the same paths, the same Docker — so "works on my machine" actually means it works.