Skip to main content
Optimizing WSL2 for Claude Code: Complete Performance Tuning Guide (2026)

Claude CodeWSL2PerformanceAI DevelopmentDeveloper Tools

Optimizing WSL2 for Claude Code: Complete Performance Tuning Guide (2026)

Updated 33 min read

The single biggest performance fix for Claude Code on WSL2 is keeping your projects on the Linux filesystem (~/projects), not on a Windows drive under /mnt/c; after that, the work is sizing .wslconfig, choosing a networking mode, and installing the two packages the sandbox needs.

I develop on Windows by choice, and WSL2 is why that still works: a real Linux kernel, ext4, and bash, without giving up the Windows desktop. This guide is the setup I run on a 64 GB, 20-thread Intel i7-13700 workstation. Every setting was checked against the current Microsoft, Anthropic, and VS Code documentation in September 2026.

Checked against: WSL 2.7.14 (the stable release, September 2026) with Linux kernel 6.18.33.2, and Claude Code 2.1.280. WSL 2.9.x is the pre-release line. Run wsl --version and claude --version to see yours.

Quick Start: The 10-Minute Path

If you only do this section, you get most of the benefit. Everything after it is detail and troubleshooting.

1. Update WSL and install a current Ubuntu (PowerShell):

wsl --update
wsl --install Ubuntu-26.04
wsl -l -v    # VERSION column must say 2

Ubuntu 24.04 LTS works just as well; if you already have it, keep it. If an existing distribution shows version 1, convert it with wsl --set-version <DistroName> 2.

2. Create C:\Users\<you>\.wslconfig sized for your machine (see the sizing table below; this is the 64 GB version):

[wsl2]
memory=48GB
processors=20
swap=16GB

Then restart WSL from PowerShell with wsl --shutdown.

3. Turn on systemd inside WSL, if your distribution does not already:

printf '[boot]\nsystemd=true\n' | sudo tee -a /etc/wsl.conf

Check first with cat /etc/wsl.conf; if a [boot] section already exists, edit it instead of appending a second one. Run wsl --shutdown again after changing it.

4. Put your code on the Linux side:

mkdir -p ~/projects && cd ~/projects
git clone https://github.com/your-org/your-repo.git

5. Install Claude Code and the sandbox dependencies inside WSL:

curl -fsSL https://claude.ai/install.sh | bash
sudo apt-get update && sudo apt-get install -y bubblewrap socat

6. Verify and start:

claude doctor
cd ~/projects/your-repo && claude

On first launch, sign in. The browser opens on Windows and shows a code; paste it back into the terminal. Then run /sandbox inside Claude Code to turn on sandboxing (on Ubuntu 24.04 or later, read the AppArmor note in the Sandbox section first).

What Changed in 2026

WSL

  • The stable line moved to WSL 2.7 with a 6.18 kernel (from 6.6 in late 2025).
  • Sparse VHDs are disabled. WSL ignores sparseVhd=true because of a data-corruption bug, and --set-sparse true now demands --allow-unsafe. If you followed older advice, including an earlier version of this guide, remove it. Details under Disk Space.
  • Microsoft now points people to the WSL Settings app (Start menu) for editing .wslconfig.
  • The virtioproxy fallback networking mode is renamed Consomme in the 2.9 pre-releases, which also add a public preview of WSL Containers (a wslc command for building and running Linux containers) and a wsl --manage <distro> --compact command.
  • Ubuntu 26.04 LTS is available as a WSL distribution.

Claude Code

  • The native installer is the default everywhere. The npm package still works but, as of v2.1.198, requires Node.js 22 or later, and it installs the same native binary.
  • claude doctor runs read-only diagnostics without starting a session, including settings-file validation and the result of the last auto-update.
  • The sandbox runs on WSL2 (not WSL1 or native Windows) and gained credential masking: a sandboxed command can read a placeholder where a token sits in a file, with the real value substituted only on requests to hosts you allow.
  • The Claude Desktop app's Code tab can run sessions inside a WSL 2 distribution.
  • Native builds no longer start on WSL1 (see below).

Why WSL2 for Claude Code

Claude Code's setup documentation offers three ways to run on Windows:

ModeSandboxingBest for
Native Windows (PowerShell or CMD installer)Not supportedWindows-native projects and tools
WSL 2SupportedLinux toolchains or sandboxed command execution
WSL 1Not supportedOnly if WSL 2 is unavailable

WSL2 is the right choice when your toolchain is Linux:

  • The sandbox only runs there. On Linux and WSL2 the sandbox uses bubblewrap, which needs kernel features WSL1 lacks.
  • ext4 is fast; /mnt/c is not. See the measurements below.
  • The Linux toolchain runs natively: git, build tools, language runtimes, Docker Engine.

WSL1 has a further problem: since Claude Code 2.1.83 the native binary fails on WSL1 with Exec format error (#38788). The install troubleshooting page gives a dynamic-linker workaround, but its first recommendation is converting to WSL2.

WSL itself has been open source under the MIT license since Build 2025. The WSL1 kernel driver (Lxcore.sys) and the \\wsl.localhost redirector remain closed.

Installation in Detail

Claude Code's minimum requirements are Windows 10 1809+, Ubuntu 20.04+ or Debian 10+, and 4 GB of RAM. The native installer puts a launcher at ~/.local/bin/claude and updates itself in the background. To follow the stable channel (typically about a week behind, skipping releases with major regressions):

curl -fsSL https://claude.ai/install.sh | bash -s stable

You can also switch later with /config or by setting "autoUpdatesChannel": "stable" in ~/.claude/settings.json. Homebrew and WinGet installs do not auto-update by default.

npm pitfalls on WSL

These apply only if you installed with npm. Per the install troubleshooting page:

  • Platform mismatch: WSL is picking up the Windows npm. Run npm config set os linux, then npm install -g @anthropic-ai/claude-code --force. Do not use sudo.
  • exec: node: not found: which node points to /mnt/c/.... Install Node inside WSL with your package manager or nvm.
  • nvm conflicts: WSL imports the Windows PATH, so the Windows nvm can win. Load nvm in ~/.bashrc:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

Anthropic's docs warn against fixing PATH conflicts with appendWindowsPath = false, because that breaks calling Windows executables (code ., explorer.exe ., powershell.exe) from WSL.

Signing in from WSL2

The login browser opens on Windows, so its redirect usually cannot reach Claude Code's callback inside WSL. After you sign in, the browser shows a code; paste it at the Paste code here if prompted prompt. If no browser opens at all, point BROWSER at a Windows browser:

export BROWSER="/mnt/c/Program Files/Google/Chrome/Application/chrome.exe"

If pasting does nothing, try Shift+Insert or right-click in Windows Terminal, or run claude auth login, which reads the code from standard input. The same BROWSER setting helps other CLIs that open a browser for OAuth, such as gh auth login.

Filesystem: The Single Biggest Win

Microsoft's file system guidance is direct: for the fastest performance from a Linux command line, store your files in the WSL file system. Windows drives under /mnt/c are reached over the 9P protocol, and every file operation crosses the VM boundary.

What I measured

I reran this on the workstation above in September 2026 (WSL 2.7.13, kernel 6.18.33.2, Windows C: drive for the /mnt/c case). The workload was a shallow clone of the microsoft/WSL repository (1,487 tracked files), placed once on ext4 and once under /mnt/c. Times are medians of five warm runs (three for the clone).

OperationLinux ext4 (~/)Windows NTFS (/mnt/c)
git status0.004 s1.05 s
Local git clone --no-hardlinks0.39 s5.6 s
Sequential write, dd bs=1M count=1024 conv=fdatasync oflag=direct5.2 to 6.6 GB/sabout 300 MB/s

These numbers are one machine and one repository; your ratios will differ with disk, antivirus, and project shape. The pattern will not: operations that touch many small files, which is most of what git and Claude Code do, pay the largest penalty. An earlier run of the same dd test on this machine in March 2026 showed about 1.0 GB/s against 110 MB/s, so treat the sequential figure as the least stable of the three.

For the overhead of WSL2 itself, Phoronix measured Ubuntu 24.04 under WSL2 on Windows 11 25H2 at about 87% of bare-metal Ubuntu across more than 50 benchmarks (September 2025). That is the cost of the VM; crossing into /mnt/c costs far more.

Anthropic's troubleshooting page adds a symptom worth knowing: on WSL, cross-filesystem read penalties can make Claude Code's search return fewer matches than expected, and claude doctor still reports Search as OK.

Moving existing projects

mkdir -p ~/projects
cp -r /mnt/d/projects/my-app ~/projects/my-app

A fresh git clone is cleaner than a copy: it drops Windows line-ending and permission artifacts. From Windows, the files are at \\wsl.localhost\Ubuntu\home\<user>\projects (replace Ubuntu with your distribution name), and explorer.exe . opens the current WSL directory in File Explorer.

Sizing .wslconfig

.wslconfig holds VM-wide settings at C:\Users\<your-username>\.wslconfig. It does not exist by default. You can edit it through the WSL Settings app or directly; the file is easier to keep under version control.

Defaults

From the current configuration reference:

SettingSectionDefault
memory[wsl2]50% of Windows RAM
processors[wsl2]All logical processors
swap[wsl2]25% of Windows RAM, rounded up to the nearest GB
networkingMode[wsl2]NAT
dnsTunneling[wsl2]true (Windows 11 22H2+)
autoProxy[wsl2]true (Windows 11)
firewall[wsl2]true (Windows 11 22H2+)
vmIdleTimeout[wsl2]60000 ms
autoMemoryReclaim[experimental]dropCache
sparseVhd[experimental]false (and currently ignored if set)

On Windows 11 22H2 and later, DNS tunneling and auto-proxy are already on. You do not need to set them.

Where the memory goes

The model runs on Anthropic's servers, so Claude Code's own footprint is modest. On my machine, two long-running sessions each held 450 to 510 MB resident (ps, Claude Code 2.1.280). The real load is what Claude runs: test suites, builds, dev servers, language servers, Docker containers. Parallel work multiplies that. Each git worktree session (claude --worktree feature-auth) is a separate checkout, often with its own node_modules, its own dev server, and its own test runs. Subagents do not add a checkout, but when several run tests or builds at once, those commands run side by side too.

Size for the number of sessions you actually run in parallel, plus whatever containers you keep up.

Sizing guidance

This table is guidance from my own setups, not a measurement:

MachinememoryprocessorsswapParallel sessions that stay comfortable
16 GB, 8 threads10GB84GB1 to 2, light builds
32 GB, 12 to 16 threads22GBall8GB2 to 4
64 GB, 16 to 24 threads48GBall16GB4 to 8, with Docker
128 GB, 24+ threads96GBall16GB to 32GB8+, or a local model alongside

The rule behind it: leave Windows enough for the browser, IDE, and chat apps you keep open (6 GB at the low end, 16 GB or more at the top), and subtract Docker Desktop's allocation if you use Docker Desktop rather than Docker Engine inside WSL. memory is a ceiling, not a reservation. If Windows gets sluggish during heavy parallel builds, set processors two below your thread count.

A tuned .wslconfig

# C:\Users\<your-username>\.wslconfig

[wsl2]
# Ceiling, not a reservation
memory=48GB
# Match your logical thread count (nproc inside WSL)
processors=20
# Headroom for build spikes; better to swap than to OOM-kill a session
swap=16GB
# Optional: see Networking. Requires Windows 11 22H2+.
networkingMode=mirrored

[experimental]
# Optional: release cached memory slowly instead of all at once
autoMemoryReclaim=gradual

autoMemoryReclaim: the default, dropCache, releases cached memory immediately when WSL is idle; gradual releases it slowly. Either returns memory to Windows.

sparseVhd is left out on purpose. In the WSL source, a sparseVhd=true setting is overridden at VHD creation with a warning ("Sparse VHD support is currently disabled due to potential data corruption"), and wsl --manage <distro> --set-sparse true refuses to run without --allow-unsafe. Reclaim disk space manually instead.

Applying changes

Run wsl --shutdown in PowerShell, then reopen your terminal. If you close WSL without the shutdown, allow about eight seconds for the VM to stop before relaunching, or the old settings stay in effect. wsl --list --running tells you whether anything is still up.

Configuring /etc/wsl.conf

/etc/wsl.conf holds per-distribution settings. The two worth adding:

# /etc/wsl.conf
[boot]
systemd=true

[automount]
options="metadata"

systemd=true (default false in Microsoft's reference): needed for Docker Engine, cron, and anything run as a systemd unit, and for systemctl reload apparmor in the sandbox setup.

metadata (default disabled): stores Linux permissions on files under /mnt/c. It matters only if you still touch Windows drives.

Everything else ships with a sensible default: appendWindowsPath=true, generateResolvConf=true, GPU support on, Windows timezone sync on. Leave them.

Settings, Environment Variables, and Credentials

Where settings live

Claude Code reads ~/.claude/settings.json (you, every project), .claude/settings.json (committed, shared with the team), and .claude/settings.local.json (you, one project, kept out of git). The settings reference covers precedence. All of these live inside WSL; a Windows-side install of Claude Code keeps its own separate %USERPROFILE%\.claude.

Environment variables can go in a settings file's env block instead of .bashrc, which also makes them apply when Claude Code is launched from an IDE rather than your shell:

{
  "env": {
    "DISABLE_AUTOUPDATER": "1"
  }
}

Variables worth knowing

Per the environment variable reference and data usage page:

VariableEffect
DISABLE_AUTOUPDATER=1Stops background updates; claude update still works
DISABLE_TELEMETRY=1Opts out of usage metrics; also turns off the feature-flag evaluation Remote Control depends on
DISABLE_ERROR_REPORTING=1Opts out of error reports
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1All of the above plus release notes and similar checks. Setting it to 0 still disables them; unset it to re-enable
HTTPS_PROXY, NO_PROXYProxy routing (see Networking)
NODE_EXTRA_CA_CERTSExtra CA bundle for TLS-inspecting proxies
BROWSERWhich browser opens for sign-in

API keys

If you sign in with a Pro, Max, Team, or Enterprise subscription, do not export ANTHROPIC_API_KEY in .bashrc. Once approved, that key takes precedence over your subscription login, and in -p mode it is always used when present. A stale key from an old project is a common cause of This organization has been disabled errors. Run /status to see which credential is active.

If you do bill through an API key, keep it out of any file that could be committed. I have pushed keys to public repos twice; provider secret scanning caught it both times, which is a safety net, not a plan. Load it from a secrets manager at shell start:

export ANTHROPIC_API_KEY=$(pass show anthropic/api-key)

Git credentials

For HTTPS remotes, point WSL's Git at Git Credential Manager from Git for Windows, as the GCM WSL guide shows:

git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/bin/git-credential-manager.exe"

The path may differ on your install. Tokens then live in the Windows credential store, shared with Windows-side Git.

SSH keys and agents

Two workable setups:

  • Keys inside WSL. Generate or copy keys into ~/.ssh (mode 600) and run a Linux ssh-agent. Simplest, and nothing crosses the VM boundary.
  • Use the Windows agent. If your keys live in a Windows agent (1Password, or the Windows OpenSSH agent service), have Git in WSL call the Windows ssh.exe, as 1Password's WSL guide documents:
git config --global core.sshCommand ssh.exe
ssh-add.exe -l    # confirm the agent is reachable

With the second setup and the sandbox's seccomp filter installed, a sandboxed git push cannot launch ssh.exe (see Sandbox). Push from outside the sandbox or allow it explicitly.

Networking

NAT versus mirrored

WSL2 defaults to NAT. In NAT mode, Windows reaches Linux servers on localhost, but Linux cannot reach Windows servers on localhost. Mirrored mode, available on Windows 11 22H2 and later, fixes that, and Microsoft's networking documentation recommends trying it. It adds:

  • Linux-to-Windows connections on 127.0.0.1 (IPv6 ::1 is not supported)
  • IPv6 and multicast
  • Better VPN compatibility
  • Direct access to WSL from your LAN

When to switch: something inside WSL needs a server running on Windows (an MCP server, a database, a local model server), a VPN misbehaves under NAT, or JetBrains IDE detection fails. If none of that applies, NAT works fine for Claude Code in a terminal.

Docker Desktop: Docker has supported mirrored mode since Desktop 4.26 (WSL 2.0.4 or later required), and the 2023 Kubernetes startup failure under mirrored mode (docker/for-win#13807) was closed as fixed. If a published port still fails to bind after switching, go back to NAT for that machine.

Mirrored mode sits behind the Hyper-V firewall, which is on by default. To accept inbound connections into WSL, Microsoft documents allowing them in an admin PowerShell:

Set-NetFirewallHyperVVMSetting -Name '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' -DefaultInboundAction Allow

Staying on NAT but need a Windows-side service? Use the Windows host's address instead of localhost:

ip route show | grep -i default | awk '{ print $3 }'

DNS

DNS tunneling (on by default on Windows 11 22H2+) answers DNS requests through Windows instead of over packets, which helps with VPNs. If resolution still fails, write a static resolver. First set this in /etc/wsl.conf (edit the existing [network] section if there is one rather than adding a second):

[network]
generateResolvConf=false

Then replace the generated file and restart WSL:

sudo rm /etc/resolv.conf
printf 'nameserver 1.1.1.1\nnameserver 8.8.8.8\n' | sudo tee /etc/resolv.conf
# then, from PowerShell: wsl --shutdown

Corporate networks often need their own resolvers for internal names; use those instead of public ones.

Corporate proxies and TLS inspection

With autoProxy on, WSL inherits the Windows proxy. Claude Code also reads the standard variables, per its network configuration page:

export HTTPS_PROXY="http://proxy.corp.example.com:8080"
export NO_PROXY="localhost,127.0.0.1,.corp.example.com"

The native binary trusts both its bundled CA set and the OS store, so a TLS-inspection proxy works once its root certificate is in the distribution's trust store:

sudo cp corp-root.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

Otherwise point NODE_EXTRA_CA_CERTS at the PEM file.

Sandbox: End to End

The sandbox runs the Bash commands Claude issues under OS-level filesystem and network isolation, which is what makes it reasonable to let routine commands run without a prompt each time. On WSL2 the sandboxing docs describe this path.

1. Install the dependencies:

sudo apt-get install bubblewrap socat

bubblewrap enforces filesystem isolation; socat relays network traffic through the sandbox proxy. The optional seccomp filter, which blocks Unix domain sockets, installs with npm install -g @anthropic-ai/sandbox-runtime.

2. Clear the AppArmor restriction on Ubuntu 24.04 and later. AppArmor can stop bubblewrap from creating user namespaces, including inside WSL2. Check:

sysctl kernel.apparmor_restrict_unprivileged_userns

If it returns 0, or the key does not exist, skip ahead. If it returns 1, add a profile for bwrap only (not the commands it runs), from the sandboxing docs:

sudo tee /etc/apparmor.d/bwrap > /dev/null <<'EOF'
abi <abi/4.0>,
include <tunables/global>

profile bwrap /usr/bin/bwrap flags=(unconfined) {
  userns,
  include if exists <local/bwrap>
}
EOF
sudo systemctl reload apparmor

3. Turn it on. Restart Claude Code and run /sandbox. If only a Dependencies tab appears, something required is missing. On the Mode tab, choose auto-allow (sandboxed commands run without prompting) or regular permissions (prompts stay). The choice saves to .claude/settings.local.json for that project. To enable it everywhere, put it in ~/.claude/settings.json:

{
  "sandbox": {
    "enabled": true,
    "network": {
      "allowedDomains": ["github.com", "*.npmjs.org", "registry.npmjs.org"]
    },
    "excludedCommands": ["docker *"]
  }
}

By default sandboxed commands can write to the working directory, the session temp directory, and directories added with --add-dir. A command that needs a new domain prompts the first time; allowedDomains pre-approves the ones you know. docker is incompatible with the sandbox, which is why the docs recommend excluding it.

4. Know the WSL-specific edges.

  • Windows binaries. WSL launches Windows programs (cmd.exe, powershell.exe, ssh.exe, anything under /mnt/c) over a Unix socket. With the seccomp filter installed, a sandboxed command cannot start them. Either add those commands to excludedCommands or set sandbox.network.allowAllUnixSockets to true, which reopens that interop socket along with every other Unix socket.
  • Clipboard. clip.exe, xclip, and wl-copy can fail from inside the sandbox. Use /copy, which writes from the Claude Code process itself.
  • Fallback. If the sandbox cannot start, Claude Code warns and runs commands unsandboxed. Set sandbox.failIfUnavailable to true if you would rather it refuse to start.

To try it for one session without touching settings files:

claude --settings '{"sandbox": {"enabled": true, "allowUnsandboxedCommands": false}}'

Hooks and Notifications

Getting told when Claude is waiting

By default Claude Code sends desktop notifications only in Ghostty, Kitty, and iTerm2, per its terminal configuration page. In Windows Terminal or VS Code, ring the terminal bell instead:

{
  "preferredNotifChannel": "terminal_bell"
}

Then make the bell visible in Windows Terminal. Its bellStyle profile setting accepts "all", "audible", "window", "taskbar", or "none"; "all" plays a sound and flashes the taskbar icon, and only flashes it when the window is out of focus. In Windows Terminal's settings.json, under profiles.defaults or your Ubuntu profile:

"bellStyle": "all"

For a dialog instead, Anthropic's hooks guide gives a Notification hook that calls powershell.exe through WSL interop:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')\""
          }
        ]
      }
    ]
  }
}

The dialog can open behind your terminal window. Test the command in a WSL shell first.

Formatting after edits

Hooks run inside WSL, so Linux tools just work. This PostToolUse hook from the same guide runs Prettier on each file Claude edits; put it in the project's .claude/settings.json and install jq (sudo apt-get install jq):

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

The WSL-specific rule for hooks: a hook that calls a Windows .exe depends on interop being on and the Windows PATH being appended, which are the defaults. Keep project hooks on Linux tools where you can, so teammates on macOS and Linux can run them too.

Terminal and Editor Integration

Windows Terminal

Windows Terminal is the right host for a WSL Claude Code session. Shift+Enter inserts a newline without setup. Set the bell as above, and if you use tmux inside WSL, add the tmux lines from Claude Code's terminal configuration page so Shift+Enter and notifications pass through.

VS Code

Install the WSL extension, then from a WSL terminal:

cd ~/projects/my-app
code .

The title bar shows [WSL: Ubuntu], and the VS Code server runs inside WSL. Open projects from the Linux side; some extensions need a separate install in the WSL context, and VS Code prompts for them.

In the integrated terminal, run /terminal-setup once inside Claude Code. It adds the Shift+Enter keybinding and turns off terminal GPU acceleration to prevent garbled text. VS Code's files.watcherExclude default already covers node_modules and parts of .git; add your build output:

{
  "files.watcherExclude": {
    "**/dist/**": true,
    "**/build/**": true
  }
}

The Claude Code VS Code extension bundles its own copy of the CLI for its panel. If you want claude in a terminal too, run the standalone installer inside WSL.

JetBrains

If Claude Code reports "No available IDEs detected" with a JetBrains IDE on Windows, the cause is usually NAT networking or the Windows firewall. The JetBrains integration docs recommend a firewall rule first, because it keeps your networking mode. Find your subnet with hostname -I inside WSL (for 172.21.123.45, the subnet is 172.21.0.0/16), then in an admin PowerShell:

New-NetFirewallRule -DisplayName "Allow WSL2 Internal Traffic" -Direction Inbound -Protocol TCP -Action Allow -RemoteAddress 172.21.0.0/16 -LocalAddress 172.21.0.0/16

The alternative is networkingMode=mirrored. For the plugin's Claude command, the docs give wsl -d Ubuntu -- bash -lic "claude".

Claude Desktop

The Desktop app's Code tab can run a session inside a WSL 2 distribution: pick the distribution from the environment picker's WSL section, then a Linux folder. Claude Code, its tools, and git execute inside Linux. Some features are unavailable there, including @mentions, the plugin browser, and connectors.

Clipboard and Images

  • Paste an image: Alt+V on Windows and WSL (not Ctrl+V), per the interactive mode reference.
  • If paste reports no image under WSLg, you are probably hitting #89223. Save the screenshot to a file and give Claude the path instead. wslpath converts a Windows path:
wslpath 'C:\Users\me\Pictures\Screenshots\error.png'
# /mnt/c/Users/me/Pictures/Screenshots/error.png
  • Copy out: /copy puts Claude's last response, or a single code block from it, on your clipboard and also writes it to a file.

MCP Servers on WSL

An MCP server configured in Claude Code inside WSL runs inside WSL. Add it with the CLI:

claude mcp add --transport stdio my-server -- npx -y @my-org/mcp-server
claude mcp list

--scope user makes it available in every project; project-scoped servers go in a committed .mcp.json, which each person approves on first use. The MCP docs cover scopes.

WSL-specific points:

  • Use Linux paths in server arguments. A server that needs Windows files can take /mnt/c/..., at /mnt/c speed.
  • nvm and PATH. If npx comes from nvm, a server launched outside your interactive shell may not find it. Give the full path, such as ~/.nvm/versions/node/<version>/bin/npx.
  • Import from Claude Desktop. If you configured servers in Claude Desktop on Windows, claude mcp add-from-claude-desktop copies them into Claude Code inside WSL. Check the imported commands afterward: a Windows npx.cmd or C:\ path will not run in Linux.
  • A server running on Windows (for example one bound to a Windows-only app) is reachable over HTTP from WSL: at http://localhost:<port> in mirrored mode, or at the host IP from the Networking section in NAT mode, with the server listening on more than loopback. Add it with --transport http.
  • Sandbox: MCP servers are separate from the Bash sandbox, but a server that shells out to Windows binaries hits the same interop rules.

File Watching

Claude Code, VS Code, language servers, and dev servers all use inotify watches. The old 8,192 default no longer applies: since Linux 5.11, the default scales with memory, using up to 1% of RAM, between 8,192 and 1,048,576 watches. A WSL2 VM with tens of gigabytes starts in the hundreds of thousands. Check before changing anything:

cat /proc/sys/fs/inotify/max_user_watches

If you hit ENOSPC watch errors, raise it the way VS Code's Linux docs describe:

echo "fs.inotify.max_user_watches=524288" | sudo tee /etc/sysctl.d/60-inotify.conf
sudo sysctl --system

Each watch costs about 1,080 bytes, so 524,288 watches in use is roughly 540 MiB of kernel memory at the upper bound.

Changes made by Windows programs to files under /mnt/c still do not reliably fire inotify events inside WSL2 (microsoft/WSL#4739, open). One more reason to keep projects on ext4.

GPU and Local Models

If you run local models alongside Claude Code, WSL2 passes NVIDIA GPUs through without a Linux driver. Per NVIDIA's CUDA on WSL guide: install the latest Windows production driver (CUDA on WSL needs R495 or later) and do not install an NVIDIA driver inside WSL. Pascal or later is recommended. Verify with nvidia-smi. Limits: no full Unified Memory, limited pinned memory, and with the NVIDIA Container Toolkit only --gpus all works on multi-GPU machines.

Model weights count against .wslconfig memory when they load into system RAM, so a machine that runs a local model and several Claude Code sessions belongs in the top row of the sizing table. For what a dedicated local-model box takes, see the private LLM option.

Disk Space

Each distribution lives in an ext4.vhdx that grows as you add files and does not shrink when you delete them. With sparse VHDs disabled, reclaim space manually. Inside WSL:

sudo fstrim /

Then, in an admin PowerShell, find the VHD and compact it (Optimize-VHD needs the Hyper-V PowerShell module):

wsl --shutdown
$vhd = (Get-ChildItem HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss |
  Where-Object { $_.GetValue("DistributionName") -eq "Ubuntu" }).GetValue("BasePath") + "\ext4.vhdx"
Optimize-VHD -Path $vhd -Mode Full

Without Hyper-V tools, use diskpart from an elevated prompt: select vdisk file="<path to ext4.vhdx>", attach vdisk readonly, compact vdisk, detach vdisk.

Before compacting, find what is actually using space. The usual suspects on a Claude Code machine are node_modules in old worktrees, Docker images, and package caches:

du -xh --max-depth=2 ~ 2>/dev/null | sort -h | tail -20
docker system df    # if you use Docker

WSL 2.5 and later also manage disks from the command line, per Microsoft's disk space guide:

wsl --manage Ubuntu --resize 500GB     # expand the VHD
wsl --manage Ubuntu --move D:\WSL\Ubuntu
wsl --install Ubuntu-26.04 --vhd-size 100GB

Keeping It Current

  • WSL: wsl --update from PowerShell. wsl --update --pre-release opts into the 2.9 line. Check with wsl --version.
  • Ubuntu: sudo apt update && sudo apt upgrade.
  • Claude Code: native installs update in the background; claude doctor shows the last attempt. claude update applies an update immediately. To stay on stable without being downgraded from a newer build, /config offers to pin minimumVersion when you switch channels.

Troubleshooting by Symptom

Everything is slow. Check: pwd. If it starts with /mnt/, that is the cause. Fix: move the project to ~/projects. Then check free -g against your .wslconfig memory and top for a runaway build or test process.

Search misses files it should find. Check: is the project under /mnt/c? claude doctor reports Search as OK even when cross-filesystem reads are losing results. Fix: move the project, or narrow the search to a directory.

claude: command not found after installing. Check: echo $PATH | tr ':' '\n' | grep -Fx "$HOME/.local/bin". Fix: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc.

cannot execute binary file: Exec format error. Check: wsl -l -v in PowerShell. Version 1 is the cause. Fix: wsl --set-version <DistroName> 2.

Can't sign in; the browser never returns to the terminal. Check: whether the browser shows a code after sign-in. Fix: paste the code at the prompt, set BROWSER to a Windows browser if nothing opened, or use claude auth login. If you see This organization has been disabled, unset a stale ANTHROPIC_API_KEY.

"Unable to connect to Anthropic services" or timeouts. Check: curl -I https://api.anthropic.com from the same shell, and env | grep -i proxy. Fix: if curl fails, it is WSL networking, not Claude Code: see DNS and proxy above, and try networkingMode=mirrored on a VPN. If curl works but Claude Code does not, the proxy or CA settings differ between the two; check HTTPS_PROXY and NODE_EXTRA_CA_CERTS.

DNS works on Windows but not in WSL. Check: cat /etc/resolv.conf and getent hosts api.anthropic.com. Fix: confirm DNS tunneling is on (the default on Windows 11 22H2+), then fall back to a static resolver.

The VHD keeps growing. Check: the size of ext4.vhdx in Explorer, then du inside WSL. Fix: delete what du finds, sudo fstrim /, then compact. Do not enable sparse mode.

File changes are not picked up (dev server, tests in watch mode, VS Code). Check: is the project under /mnt/c? Then cat /proc/sys/fs/inotify/max_user_watches. Fix: move the project to ext4; raise the watch limit only if you see ENOSPC.

IDE not detected. Check: which IDE. For JetBrains on Windows, NAT is the usual cause. For VS Code, confirm the window is connected to WSL ([WSL: Ubuntu] in the title bar) and you launched claude from its integrated terminal. Fix: the firewall rule or mirrored mode for JetBrains; code . from WSL for VS Code.

Sandbox will not start. Check: /sandbox for a Dependencies tab, and sysctl kernel.apparmor_restrict_unprivileged_userns. Fix: install bubblewrap and socat, add the AppArmor profile if the sysctl returns 1, restart Claude Code.

Sandboxed command cannot run powershell.exe or ssh.exe, or the clipboard stays empty. Check: whether the seccomp filter is installed (it blocks the interop socket). Fix: add the Windows command to sandbox.excludedCommands. For the clipboard, use /copy; excluding clipboard tools does not take a piped call out of the sandbox on its own.

claude doctor or claude update hangs with no output. Check: ls -ld ~/.bashrc ~/.profile. A directory at a shell config path caused this before v2.1.214. Fix: move the directory aside, or rerun the install script.

Claude Code hangs intermittently. Check: whether it recurs after claude update. Fix: no confirmed root cause yet; see #619 and file a report with /feedback if you can reproduce it.

Known Issues

Open WSL-specific issues on anthropics/claude-code as of September 23, 2026:

  • Claude in Chrome is not supported under WSL. The Chrome integration docs say so directly; #93124 tracks the gap.
  • Image paste fails under WSLg (#89223): pasting a Windows screenshot reports no image, because wl-paste returns BMP data.
  • Clickable file links do nothing (#85643): Claude Code emits file:///home/... links that Windows cannot resolve.
  • Intermittent hangs (#619): open since March 2025, with no confirmed root cause.

Earlier versions of this guide listed eight other WSL issues: #2364 (fetch failed on a clean install), #2481 (connection errors that disabling telemetry cleared), #332 (corporate proxy, closed as completed), #1232 (JetBrains detection, closed as completed; the fix is now in the JetBrains docs above), #20115 (interactive mode exits on launch), #14550 (intermittent connection drops), #16429 (VS Code extension delays), and #15362 (Claude in Chrome crashes). Except for the two marked completed, all were closed by the inactivity bot without a confirmed fix. If you hit one, the troubleshooting steps above come first, and a new report beats a comment on a locked thread. The Bun segfault report (#21875) is still open, but its reporter wrote in April 2026 that it no longer reproduces on current versions.

FAQ

Should I use WSL1 or WSL2 for Claude Code? WSL2. It is the only Windows option that supports Claude Code's sandbox, it gives you ext4 for your projects, and current native builds of Claude Code fail to start on WSL1 with an Exec format error unless you apply a workaround.

Why is Claude Code slow on WSL2? Usually because the project is on a Windows drive (/mnt/c or /mnt/d). Every file operation there crosses the 9P bridge; on my machine git status took 1.05 seconds under /mnt/c against 4 milliseconds on ext4. Move the project to ~/projects, then check that .wslconfig gives WSL enough memory.

How much RAM should I allocate to WSL2 for Claude Code? The default is 50% of Windows RAM. Raise it to what Windows and your desktop apps can spare, for example 48 GB of 64 GB, and size for the builds, tests, and containers your parallel sessions run, since Claude Code itself uses about half a gigabyte per session. The value is a ceiling, and autoMemoryReclaim returns cached memory to Windows when WSL is idle.

Should I use mirrored networking with Docker Desktop? You can. Docker Desktop has supported WSL mirrored mode since version 4.26. Switch to mirrored when you need WSL to reach Windows services on localhost or when a VPN misbehaves, and fall back to NAT if a published port fails to bind.

Does Claude Code's sandbox work on WSL2? Yes. Install bubblewrap and socat, and on Ubuntu 24.04 or later check whether AppArmor restricts unprivileged user namespaces; if it does, add the bwrap profile from Anthropic's sandboxing docs. It does not work on WSL1 or native Windows.

Can MCP servers running on Windows be used from Claude Code in WSL? Yes, over HTTP. In mirrored mode the server is reachable at localhost; in NAT mode use the Windows host IP from ip route show. Stdio servers run where Claude Code runs, so they must be Linux commands inside WSL.

How do I get a notification when Claude Code needs input on WSL? Set preferredNotifChannel to terminal_bell in ~/.claude/settings.json and set bellStyle to all or taskbar in Windows Terminal, which flashes the taskbar icon. For a dialog, use a Notification hook that calls powershell.exe.

How do I fix DNS resolution in WSL2? DNS tunneling is already on by default on Windows 11 22H2 and later. If lookups still fail, set generateResolvConf=false under [network] in /etc/wsl.conf, replace /etc/resolv.conf with static nameservers, and run wsl --shutdown.

Does Claude Code work behind a corporate VPN or proxy on WSL2? Yes, with configuration. autoProxy passes the Windows proxy into WSL, Claude Code honors HTTPS_PROXY and NO_PROXY, and a TLS-inspection root certificate must be in the distribution's trust store or named in NODE_EXTRA_CA_CERTS. Mirrored networking often helps with VPN clients.

How do I share Git credentials and SSH keys between Windows and WSL2? For HTTPS, set Git in WSL to use Git Credential Manager from Git for Windows. For SSH, either keep keys and an agent inside WSL, or set core.sshCommand to ssh.exe so Git uses the Windows agent.

Checklist

  • WSL current (wsl --update; wsl --version shows 2.7.x or later)
  • Distribution on WSL 2 (wsl -l -v), Ubuntu 24.04 or 26.04 LTS
  • Projects on ext4 (~/projects), not /mnt/c
  • .wslconfig sets memory, processors, swap for your parallel workload; no sparseVhd
  • networkingMode=mirrored only if you need WSL-to-Windows localhost, VPN compatibility, or JetBrains detection (Windows 11 22H2+)
  • /etc/wsl.conf has systemd=true
  • Claude Code from the native installer; claude doctor clean
  • bubblewrap and socat installed; AppArmor checked; /sandbox shows no Dependencies tab
  • No stray ANTHROPIC_API_KEY in .bashrc if you use a subscription (/status to check)
  • Git credentials and SSH agent set up once, on one side
  • Notifications reach you (terminal bell plus Windows Terminal bellStyle, or a hook)
  • MCP servers use Linux commands and paths
  • VS Code opened from the WSL side; /terminal-setup run in its terminal
  • VHD trimmed and compacted when it grows

Sources

Anthropic / Claude Code: Advanced setup · Troubleshoot installation · Troubleshooting · Error reference · Sandboxing · Settings · Environment variables · Data usage · Network configuration · Terminal configuration · Hooks guide · Interactive mode · Worktrees · MCP · JetBrains · Desktop in WSL · Chrome

Microsoft: WSL advanced settings · WSL networking · Working across file systems · WSL disk space · WSL open source · WSL releases · WSL#4739 · Windows Terminal profile settings · VS Code on Linux (file watcher limits) · VS Code: Developing in WSL

Other: Docker Desktop release notes · NVIDIA CUDA on WSL · Linux 5.11 inotify default · Git Credential Manager on WSL · 1Password SSH agent with WSL · Phoronix: WSL2 on Windows 11 25H2

Working on something like this?

Tell us about the work you want carried. A short email is enough to start.

Talk to us