← Back to dashboard
wsltoolingfresh

WSL — Linux on Windows Developer Guide

What is WSL?

The real model

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.

Where do the files live?
Which OS's tools touch them?
Linux fs
~/code
cross
Windows /mnt/c
C:\Users
● files here
Relative I/O speed≈ 2–20× slower
from Linux: /mnt/c/Users/you/code/your-repo
from Windows: C:\Users\you\code\your-repo
✗ Slow: The classic mistake. Linux tools on /mnt/c cross the OS boundary on every file op — 2–20× slower. Move the repo to ~/code.

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.

Text
██╗    ██╗███████╗██╗
██║    ██║██╔════╝██║
██║ █╗ ██║███████╗██║
██║███╗██║╚════██║██║
╚███╔███╔╝███████║███████╗
 ╚══╝╚══╝ ╚══════╝╚══════╝

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

  1. Overview & architecture
  2. Install & first run
  3. WSL 1 vs WSL 2
  4. Distribution management
  5. The filesystem: interop & the performance rule
  6. Command reference
  7. Configuration: .wslconfig vs wsl.conf
  8. systemd & Linux services
  9. Interop: running Windows ↔ Linux
  10. Networking & ports
  11. Docker, GPU, USB & GUI apps
  12. Windows Terminal & shell setup
  13. VS Code in WSL
  14. Claude Code in WSL
  15. Automations & dotfiles
  16. Troubleshooting
  17. 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


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:

PowerShell
wsl --install

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

PowerShell
# 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 version

If wsl --install only prints the help text, WSL is already present — use wsl --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:

FeatureWSL 1WSL 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.

PowerShell
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 installs

4. Distribution management

PowerShell
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/--import is your portable backup and the way to move a distro off the system drive. --unregister permanently 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 arePath from LinuxPath from WindowsFast for
Linux filesystem (ext4 VHDX)/home/you/code\\wsl$\Ubuntu\home\you\codeLinux tools ✅
Windows filesystem/mnt/c/Users/you/codeC:\Users\you\codeWindows tools ✅

Keep your repos in the Linux filesystem (/home/you/...) when you work with Linux tooling (git, npm, build chains). Putting them on /mnt/c forces every file op across the OS boundary and is dramatically slower.

Bash
# 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
Bash
# Clone into the Linux fs (fast), NOT /mnt/c (slow)
mkdir -p ~/code && cd ~/code
git clone https://github.com/codeAmani-Solutions/your-repo.git

6. Command reference

All from PowerShell/CMD (use wsl.exe from inside Linux):

CommandDoes
wsl --install [-d <Distro>]Install WSL + a distro
wsl --list --onlineList installable distros
wsl -l -vList installed distros, version, state
wsl --set-version <Distro> <1|2>Convert a distro's WSL version
wsl --set-default-version 2Default version for new distros
wsl -d <Distro>Launch a specific distro
wsl --update / wsl --versionUpdate / show WSL version
wsl --shutdownStop 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 -IWSL 2 VM IP address
wsl --statusDefault distro/version + kernel info

7. Configuration: .wslconfig vs wsl.conf

Two files, two scopes:

Aspect.wslconfigwsl.conf
ScopeGlobal — the WSL 2 VM, all distrosPer-distro
Location%UserProfile%\.wslconfig (Windows)/etc/wsl.conf (inside the distro)
ConfiguresRAM, CPUs, swap, networking, kernelboot/systemd, automount, interop, default user
INI
# %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
INI
# /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=johndoe

Apply .wslconfig changes with wsl --shutdown (then relaunch). wsl.conf changes 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+):

Bash
sudo nano /etc/wsl.conf
INI
[boot]
systemd=true
PowerShell
wsl --shutdown        # from Windows, then relaunch the distro
Bash
systemctl status                         # verify systemd is PID 1
sudo systemctl enable --now postgresql   # manage real services
systemctl list-unit-files --type=service

9. Interop: running Windows ↔ Linux

Bash
# 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
PowerShell
# 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.

Bash
# 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
INI
# %UserProfile%\.wslconfig — mirrored mode for VPNs / IPv6 / better localhost
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true       # inherit Windows HTTP proxy

From 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 docker CLI 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-win project (usbipd attach --wsl).
  • GUI apps (WSLg) — Linux GUI apps run out of the box (guiApplications=true); just sudo apt install and launch.
Bash
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.

Bash
# 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:

Bash
cd ~/code/your-repo
code .          # opens VS Code as a client; the server runs inside WSL

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

Bash
# 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 project

Why 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, and npm run 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 --update periodically so the kernel + WSL features stay current for whatever you're building.


15. Automations & dotfiles

Bash
# ~/.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"
PowerShell
# Windows-side: a scheduled nightly WSL backup (Task Scheduler / PowerShell)
wsl --export Ubuntu "D:\backups\ubuntu-$(Get-Date -Format yyyyMMdd).tar"
JSON
// .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

IssueFix
wsl --install only prints helpWSL already installed — use wsl --install -d <Distro>
Install hangs at 0.0%wsl --install --web-download -d <Distro>
Everything feels slowRepo is on /mnt/c — move it to ~/ (the Linux fs)
.wslconfig change ignoredRun wsl --shutdown, then relaunch
systemd not runningAdd [boot] systemd=true to /etc/wsl.conf, wsl --shutdown; needs WSL 0.67.6+
localhost:3000 unreachable from WindowsConfirm the server binds 0.0.0.0/localhost; try networkingMode=mirrored
VM eating RAMCap it: [wsl2] memory=8GB + autoMemoryReclaim=gradual
VPN breaks WSL networking[wsl2] networkingMode=mirrored + dnsTunneling=true
Can't access GPU/USBInstall the vendor WSL driver; for USB use usbipd-win
Distro corruptedRecover 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 .claude hook 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=gradual so 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.