30 tips and tricks with Claude Code CLI on WSL

Claude CodeWindowsLinuxPerformanceDeveloper ToolsCLI

July 28, 2026

A dense grid of teal document tiles on the left of a hard amber divider, with an amber scanning beam that weakens as it crosses and leaves the tiles beyond it faded and gapped

Running Claude Code on WSL has one failure mode that matters more than the other twenty-nine put together, and it never announces itself. On the Windows filesystem the agent does not just get slow. Anthropic's troubleshooting page says search returns fewer matches than actually exist, and claude doctor still reports Search as OK. A 2,000-file benchmark on a WSL2 box explains exactly why that happens, and once it is fixed the remaining twenty-nine are tuning.

Move the repo, or accept a search that lies#

Every WSL guide already tells you to keep code in ~ instead of /mnt/c. None of them say which operations the penalty actually lands on, and that detail is the whole story. An identical tree of 2,000 small files was built on ext4 and on the /mnt/c mount, then walked through the same seven operations three times each.

View data table
CategorySlowdown on /mnt/c (x)
git status229
Read every file116
Search contents with ripgrep103
Delete the tree73
Write 2,000 files65
Stat every file8.3
List filenames only1.1
Listing filenames across the WSL boundary is nearly free, reading them is 116 times slower, and that gap is why the agent answers short.
Slowdown on /mnt/c
  1. 1git status229 x
  2. 2Read every file116 x
  3. 3Search contents with ripgrep103 x
  4. 4Delete the tree73 x
  5. 5Write 2,000 files65 x
  6. 6Stat every file8.3 x
  7. 7List filenames only1.1 x
Source — Measured on WSL2, 2,000-file tree · 2026-07

Read that ranking bottom-up. Listing filenames costs 1.1 times normal. Reading their contents costs 116 times, and git status costs 229. Directory metadata crosses the 9p boundary almost free while file contents crawl, which is a very specific kind of trap for an agent.

Glob returns instantly, so the file list looks healthy. Grep and Read then degrade against the same tree and come back short. Nothing in the transcript distinguishes a real zero-match from a starved one, which is why the fix belongs at the top of the list rather than in a performance appendix.

    1. Move the repo. git clone it into ~/projects and delete the /mnt/c copy. Microsoft's own guidance is blunt about this, recommending against working across operating systems with your files at all.
    1. Check the mount before trusting a session. A pwd starting with /mnt/ is the tell, and df -T . names the filesystem outright, 9p for the Windows mount against ext4 for the Linux side.
    1. Scope every search if a repo genuinely cannot move. Naming a directory or a file type in the prompt cuts the file count the agent has to read, which is the documented workaround and the reason it works.
    1. Keep builds local even when source has to be shared. Point node_modules, dist, and scratch directories at ext4 paths, because a cold bun install measured 0.81s on ext4 against 2.95s across the boundary.
    1. Cross-check one string after a big search on /mnt/c. Grep for something you are certain exists, and if it comes back empty the result set was starved, not clean.
    1. Reach backwards. Windows applications can open \\wsl.localhost\Ubuntu\home\you\projects directly, so keeping the repo on Linux costs your Windows editor nothing.

Size the VM before you blame the agent#

Two stacked bars on brown kraft paper divide one machine between Linux on the left and Windows on the right, the top bar split evenly and labelled as half the RAM and every logical core, the lower bar showing a hand-set 32GB and 24 cores in amber with 8 cores left for Windows.
The WSL2 defaults hand the VM half the host memory and every core, which a long session will find.

WSL2 runs in a virtual machine whose defaults were chosen before anybody ran a long-lived agent inside one. Microsoft documents memory as defaulting to "50% of total memory on Windows" and processors as "The same number of logical processors on Windows". A four-hour Claude Code session with a dev server, a language server, and a few subagents will find both edges.

All of these live in %UserProfile%\.wslconfig on the Windows side, not inside the distro.

.wslconfig
[wsl2]
memory=32GB
swap=16GB
processors=24
networkingMode=mirrored

[experimental]
autoMemoryReclaim=gradual
sparseVhd=true
    1. Set memory explicitly. Half the host sounds generous until Windows starts swapping underneath you. A hard cap that leaves Windows a comfortable margin turns a frozen desktop into a clean OOM kill inside the VM.
    1. Give real swap. With swap present the kernel reclaims and kills quickly. With swap at zero, a runaway build thrashes the whole VM and takes your session with it.
    1. Leave cores free. Parallel subagent fan-out is sized against the cores the VM can see, not the cores your CPU has, so processors is the knob that decides how wide the agent will actually go.
    1. Reclaim gradually. The default is dropCache, which reclaims immediately. gradual hands idle RAM back slowly instead, which suits a session that goes quiet between prompts.
    1. Turn on sparseVhd. A WSL virtual disk grows and never shrinks on its own, so a few months of node_modules churn quietly eats tens of gigabytes of your Windows drive.
    1. Wait 8 seconds. Edits do nothing until the VM fully stops, which Microsoft documents as taking "about 8 seconds after closing ALL instances of the distribution shell". Run wsl --shutdown from PowerShell and wait before relaunching.

The Windows PATH tax, measured#

A walking envelope crosses a line of small light stepping stones marked 45 Linux directories and 0.215 seconds, then hits a boundary where the stones become heavy amber blocks marked 20 Windows directories and 6.379 seconds, ending at a wall labelled not found.
Three hundred failed command lookups, split by which side of the boundary the directories live on.

One developer described Claude Code on WSL as borderline unusable, with "freezing for several seconds at startup, hanging before every / command, and even stuttering while typing". That report shipped without timings, so here are some.

WSL imports the Windows PATH by default, which on a normal machine adds around twenty /mnt/c directories to every lookup. Three hundred failed command -v lookups took 6.379 seconds against that default PATH of 65 entries. With the twenty Windows entries stripped out, the same three hundred lookups took 0.215 seconds.

That is roughly 21 milliseconds burned every time something probes for a binary that is not there, and entry count alone does not explain it. Going from 65 entries to 45 is a factor of 1.4. The measured gap is a factor of 30, and the difference is that each Windows entry is a round trip across the same boundary the file benchmark punished.

    1. Measure yours first. echo $PATH | tr ':' '\n' | grep -c '^/mnt/c' tells you how many Windows directories every command miss is walking. Under five and this section is not your problem.
    1. Trim, not amputate. Anthropic's docs warn against appendWindowsPath = false because it "breaks the ability to call Windows executables from WSL", and that warning is correct for anyone who flips the switch and stops there.
    1. Re-add what matters. Disable the blanket import, then put System32 and whatever else you genuinely call back on the path by hand. Interop keeps working and the other seventeen directories stop costing you.
    1. Avoid hot paths. A cmd.exe spawn measured 34 milliseconds against 1.1 milliseconds for /bin/true. A status line refreshing every second, or a hook on every tool call, will feel that.
    1. Guard your profile. Every Bash call, hook, and status line spawns a shell that re-reads your profile, and on WSL that means re-walking the Windows PATH each time. Claude Code sets CLAUDECODE=1 in those subprocesses, so gate the expensive parts of ~/.bashrc on it.
    1. Use WSLENV. Sharing a Windows environment variable across the boundary costs nothing, while shelling out to PowerShell to read the same value costs a process spawn every time.
/etc/wsl.conf
[interop]
enabled=true
appendWindowsPath=false

Then add back exactly what you call, in ~/.bashrc, and nothing else.

terminal
export PATH="$PATH:/mnt/c/Windows/System32"

Install and login break here first#

Most WSL install failures are the same failure wearing different error messages. A Windows binary won the PATH race against its Linux counterpart, or a network callback could not find its way back across the VM boundary. Anthropic's install troubleshooting page documents five of them specifically for WSL, and the error strings are worth memorising.

    1. Install the binary. curl -fsSL https://claude.ai/install.sh | bash drops an ELF into ~/.local/share/claude/versions/ and sidesteps the entire npm and Node question. Cold start measured 93 milliseconds.
    1. Exec format error. cannot execute binary file: Exec format error is a known native-binary regression on WSL1. Convert with wsl --set-version <DistroName> 2 from PowerShell rather than working around it.
    1. Check which node. When claude prints exec: node: not found, run which node. A path starting with /mnt/c/ means WSL borrowed the Windows install, and the fix is a Linux Node from your package manager.
    1. Tell npm linux. If you install through npm anyway, npm config set os linux first, then npm install -g @anthropic-ai/claude-code --force, and never with sudo.
    1. Pick one nvm. With nvm installed on both sides, the Windows copy wins the PATH race and version switches inside WSL silently do nothing. Load the Linux nvm.sh from your shell profile explicitly.
    1. Expect a code. The OAuth redirect cannot reach a callback server inside the VM, so the browser shows a code instead of bouncing back. Paste it in, and if no browser opens at all, point BROWSER at your Windows Chrome executable.

Windows Terminal often refuses a normal paste into that login prompt. Right click or Shift+Insert usually gets the code in, and claude auth login reads the same code from standard input if the interactive prompt keeps ignoring you.

Interop tricks worth keeping on a hotkey#

A thick wall separates a lightly drawn Linux territory from a heavily drawn Windows one, cut by six amber gates labelled explorer.exe, wslpath, clip.exe, mirrored ports, docker socket and BROWSER.
The crossings that earn their keep, including the browser handoff that gets you logged in.

Everything above treats the Windows boundary as a cost. It is also the reason WSL beats a plain Linux box for this work, as long as the crossings stay deliberate and few, which is what the gates above are counting. These last six are worth teaching Claude Code about explicitly, because it will not reach for them on its own.

    1. explorer.exe dot. Running explorer.exe . opens the current WSL directory in File Explorer, which beats typing a UNC path when you need to drag a file into a Windows app.
    1. wslpath both ways. wslpath -w . prints the Windows form of a Linux path and wslpath -u converts back. Hand the output to a Windows tool instead of guessing at backslashes.
    1. Pipe to clip.exe. Ending a command with | clip.exe puts its output straight on the Windows clipboard, which is the fastest way to move a stack trace out of the terminal.
    1. Mirror the network. With networkingMode=mirrored a dev server bound inside WSL is reachable from Windows and from other machines on the LAN without port forwarding gymnastics.
    1. Enable Docker integration. Enabling WSL integration gives you a working docker command with no Linux daemon to babysit, and the socket crosses the boundary rather than the images.
    1. Audit search itself. Since claude doctor reports Search as OK even while it is coming back short, treat its verdict as a liveness check. Install your distro's ripgrep and set USE_BUILTIN_RIPGREP=0 so the Search line names a real binary path you can reason about.

The short version#

If the repo lives on /mnt/c, stop reading and move it. Nothing else on this list changes the fact that the agent's picture of your codebase is incomplete and that no warning fires when it is. Everything after that is speed, and speed you can feel.

The tuning still pays. A trimmed PATH takes the stutter out of the slash-command menu, a sized VM stops a long session from taking the desktop down with it, and a handful of interop commands turn the Windows side from a tax into a feature. Start with the filesystem though. It is the only one of the thirty that can be wrong rather than merely slow.

Worth pairing with the environment variables that actually matter and the tips that are not WSL specific, both of which assume a setup where search tells the truth.

Share

Newsletter

New posts land in your inbox when they publish. No spam, unsubscribe anytime.

Prefer RSS