You want to open a repo in VS Code and just work. Not “work” as in fight with path separators,
file watchers, line endings, and a mysterious fan noise that suggests your laptop is trying to achieve escape velocity.
VS Code Remote WSL is the first Windows dev setup that routinely feels like cheating—in the good way. But only if you
put the project in the right place, install the right bits once, and know how to diagnose the handful of failure modes
that keep showing up in real teams.
What “feels native” actually means
“Native” is not a vibe. It’s a measurable set of properties:
- Fast file I/O where your editor and tools aren’t punished for reading lots of small files.
- Predictable paths so tooling doesn’t get confused by Windows drive mounts or UNC oddities.
- Coherent Git behavior (line endings, file mode bits, case sensitivity) across Windows and Linux tools.
- Stable networking where localhost is localhost, and ports behave the same way every morning.
- Extensions run where they should—Linux extensions in Linux, UI extensions in Windows.
- Debugging ergonomics: when it’s slow or broken, you can prove why in minutes.
If you hit these, Remote WSL stops being a “Windows compromise” and becomes a solid Linux workstation with a Windows
GPU and app ecosystem attached. You edit in VS Code on Windows, but your language servers, compilers, shells, and build
caches live in WSL. That’s the deal.
A few facts that explain why WSL works (and where it bites)
Some context points that are genuinely useful when you’re deciding where to put code, why a file watcher is failing,
or why a “simple” optimization becomes a crater:
- WSL 1 (2016) translated Linux syscalls. It was clever, but had compatibility edges. WSL 2 switched to a real Linux kernel.
- WSL 2 runs Linux in a lightweight VM. That’s why kernel features work, and why you now have “VM-like” memory behavior.
- Early WSL 2 networking used NAT with a changing VM IP. Modern builds improved integration, but you still need to know which side owns the port.
- The Windows filesystem mount (/mnt/c) is convenient, not fast. Cross-OS file I/O has overhead—especially lots of tiny file ops.
- Ext4 inside WSL is the fast path. The Linux filesystem inside the VM is where builds and package managers behave like adults.
- VS Code “Remote” is not just an SSH trick. It runs a VS Code Server inside the target (WSL here), which hosts extensions and language tooling.
- Inotify limits are real. Large monorepos can exceed file watcher limits and look like “VS Code is broken” when it’s just a kernel knob.
- Case sensitivity differs by default. Windows historically case-insensitive, Linux case-sensitive. Git and tooling can get weird if you mix assumptions.
- WSL integrates with Windows processes. You can run
codefrom WSL, and call Windows executables from Linux. This is both a feature and a foot-gun.
A single opinionated takeaway: if you care about performance and sanity, keep your repo inside the WSL Linux filesystem,
not under /mnt/c. You can still open it from Windows via Remote WSL. That’s the trick.
How Remote WSL really works (so you debug it sanely)
The mental model
VS Code has two halves in this setup:
- VS Code UI (Windows): the editor window, menus, keybindings, rendering.
- VS Code Server (Linux in WSL): language servers, terminals, Git operations, debuggers, and most extensions.
When you “Open Folder in WSL,” VS Code installs (or reuses) a server component in your WSL distribution and then tunnels
editor operations over a local transport. If extensions are correctly classified, they run on the WSL side where the code is.
Where performance comes from
Most “VS Code is slow” complaints in a WSL workflow are really one of these:
- Wrong filesystem: repo on Windows drive, tools running in Linux, paying the cross-OS penalty on every stat call.
- Watchers: too many files, too low inotify limits, or a tool falling back to polling.
- Extensions: a Windows-only extension trying to interact with Linux paths, or an extension that insists on scanning your entire home directory.
- Resource limits: WSL memory ballooning, swap thrashing, or too few CPUs allocated.
- Networking mismatches: service bound to 127.0.0.1 in the wrong namespace, port forwarding assumptions, or firewall quirks.
If you can identify which bucket you’re in, you can fix it quickly. If you can’t, you’ll keep trying random “speed up VS Code”
advice until you end up with a broken shell and a sense of betrayal.
One quote worth keeping on a sticky note, paraphrased because exact wording drifts in memory: paraphrased idea
—
“Hope is not a strategy”, commonly attributed to reliability/operations culture (often linked to Gen. Gordon R. Sullivan).
The point: measure first, then change things.
The golden setup: do this, avoid that
1) Put code in the Linux filesystem
Your default should be: clone into your WSL home directory (or another ext4-backed location), and open from VS Code via Remote WSL.
This avoids the classic slow path: Linux tools doing heavy metadata churn on Windows-mounted directories.
Recommended pattern:
/home/<you>/src/<project>
Avoid:
/mnt/c/Users/<you>/src/<project>
unless the repo is tiny and you only occasionally touch it.
2) Install tooling in WSL, not in Windows (for WSL projects)
Node, Python, Go, Rust, Java toolchains: install them inside WSL if the project lives in WSL. That keeps paths, permissions,
and runtime behavior consistent. Use Windows tooling when the project is Windows-native (like .NET desktop apps).
3) Keep Git disciplined
Git is where cross-platform dev goes to die quietly. Decide:
- Where will Git run? (Answer: in WSL, for WSL repos.)
- What’s the line ending policy? (Answer: ideally LF in repos; enforce via
.gitattributes.) - Do you need file mode bits? (Probably yes for scripts; ensure you aren’t losing exec bits.)
4) Be explicit about Docker
You can run Docker Engine inside WSL, or use Docker Desktop integration. Both can be fine. The failure mode is mixing them
without realizing it, then debugging “why is my image cache missing?” at 2 a.m.
Pick one model and stick to it per machine.
5) Plan for file watchers and monorepos
Large repos need increased inotify limits and selective watching. Otherwise, your editor, test runner, or bundler flips into
polling mode and burns CPU like it’s being paid per cycle.
Joke #1: File watchers are like office gossip—fine in small doses, catastrophic when everyone subscribes to everyone.
Practical tasks: commands, outputs, and decisions (12+)
These are the bread-and-butter checks I run when Remote WSL doesn’t feel native. Each task includes a command, a realistic
output example, what it means, and the decision you make from it.
Task 1: Confirm you’re in WSL 2 (not WSL 1)
cr0x@server:~$ wsl.exe -l -v
NAME STATE VERSION
* Ubuntu-22.04 Running 2
Debian Stopped 2
What it means: Your distro is using WSL 2. Good—kernel features and compatibility are better.
Decision: If you see VERSION 1, convert it unless you have a specific WSL1-only requirement.
Task 2: Verify where your repo lives (fast path vs slow path)
cr0x@server:~$ pwd
/home/cr0x/src/payments-api
What it means: You’re on the Linux filesystem. This is the performance sweet spot.
Decision: If this prints something under /mnt/c, move the repo into /home and reopen in WSL.
Task 3: Check mount type and options (are you on /mnt/c?)
cr0x@server:~$ mount | grep -E ' /mnt/c | / '
C: on /mnt/c type drvfs (rw,noatime,uid=1000,gid=1000,metadata,case=off)
none on / type overlay (rw,relatime,lowerdir=/mnt/wslg/distro,upperdir=/mnt/wsl/upper,workdir=/mnt/wsl/work)
What it means: Windows drives show up as drvfs. They can be okay for occasional edits, not heavy builds.
Decision: If your repo is on drvfs and builds are slow, relocate it.
Task 4: Confirm VS Code Server is installed and where
cr0x@server:~$ ls -la ~/.vscode-server/bin | head
total 12
drwxr-xr-x 3 cr0x cr0x 4096 Jan 10 09:14 .
drwxr-xr-x 9 cr0x cr0x 4096 Jan 10 09:14 ..
drwxr-xr-x 6 cr0x cr0x 4096 Jan 10 09:14 1a2b3c4d5e6f7g8h9i0j
What it means: The server exists in your WSL home directory.
Decision: If this directory is missing and Remote WSL can’t connect, your install is failing—inspect logs (Task 5).
Task 5: Read Remote WSL logs from the server side
cr0x@server:~$ ls -la ~/.vscode-server/.cli/logs | tail -n 3
drwxr-xr-x 2 cr0x cr0x 4096 Jan 10 09:15 20260110T091500
drwxr-xr-x 2 cr0x cr0x 4096 Jan 10 09:20 20260110T092000
drwxr-xr-x 2 cr0x cr0x 4096 Jan 10 09:25 20260110T092500
cr0x@server:~$ tail -n 30 ~/.vscode-server/.cli/logs/20260110T092500/remoteagent.log
[2026-01-10 09:25:14.101] info Extension host started
[2026-01-10 09:25:14.223] info Listening on /run/user/1000/vscode-ipc-2f9a.sock
[2026-01-10 09:25:16.012] warn File watcher failed to start (ENOSPC)
What it means: Remote agent is up, but file watcher failed with ENOSPC (inotify limit).
Decision: Raise inotify limits (Task 10) and restart VS Code.
Task 6: Verify Git is the Linux Git (not Windows Git) for WSL repos
cr0x@server:~$ which git
/usr/bin/git
cr0x@server:~$ git --version
git version 2.34.1
What it means: You’re using Linux Git.
Decision: If which git shows a Windows path via interop, fix your PATH ordering or disable interop for this workflow.
Task 7: Detect line ending trouble before it becomes a week-long argument
cr0x@server:~$ git config --show-origin --get core.autocrlf
file:/home/cr0x/.gitconfig input
What it means: input converts CRLF to LF on commit, but leaves working tree as-is (typically LF in Linux).
Decision: For WSL repos, prefer input or false and enforce per-repo with .gitattributes.
Task 8: Check whether you’re accidentally working in a Windows path via UNC
cr0x@server:~$ ls -la /mnt/wsl | head -n 5
total 0
drwxr-xr-x 4 root root 80 Jan 10 08:01 .
drwxr-xr-x 15 root root 340 Jan 10 08:01 ..
drwxr-xr-x 2 root root 40 Jan 10 08:01 instances
drwxr-xr-x 2 root root 40 Jan 10 08:01 services
What it means: You’re looking at WSL infrastructure mounts. Not a problem by itself.
Decision: The trap is storing repos in Windows locations and opening them through a path that looks “Linux-y” but isn’t.
Keep repos in /home and you won’t care.
Task 9: Check disk usage in WSL (is your virtual disk full?)
cr0x@server:~$ df -hT / /home
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 251G 210G 29G 88% /
overlay overlay 251G 210G 29G 88% /
What it means: You’re running hot on space. Package managers and language servers do not negotiate with full disks.
Decision: Clean caches, prune Docker images, or expand the WSL virtual disk before things start failing randomly.
Task 10: Fix “ENOSPC” watcher errors (increase inotify limits)
cr0x@server:~$ cat /proc/sys/fs/inotify/max_user_watches
8192
cr0x@server:~$ sudo sh -c 'printf "fs.inotify.max_user_watches=524288\nfs.inotify.max_user_instances=1024\n" > /etc/sysctl.d/99-inotify.conf'
cr0x@server:~$ sudo sysctl -p /etc/sysctl.d/99-inotify.conf
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 1024
What it means: You raised watcher capacity.
Decision: If your repo is large (monorepo, node_modules, bazel output), this is often mandatory. Restart VS Code to reattach watchers.
Task 11: See if a tool is polling the filesystem (CPU burn clue)
cr0x@server:~$ ps aux --sort=-%cpu | head
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
cr0x 13240 85.1 3.2 2869136 528400 ? Sl 09:12 6:18 node /home/cr0x/src/payments-api/node_modules/.bin/webpack --watch
cr0x 11422 22.4 1.1 1462032 182220 ? Sl 09:14 1:41 /home/cr0x/.vscode-server/node ... extensionHost
What it means: Something is pegging CPU. Could be legitimate compilation, could be watch-mode polling.
Decision: If CPU is pegged when idle, check watcher errors (Task 5/10) and tool config (exclude build dirs, use native watchers).
Task 12: Check WSL memory pressure and swap thrash
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 15Gi 13Gi 420Mi 256Mi 1.7Gi 1.1Gi
Swap: 8.0Gi 6.5Gi 1.5Gi
What it means: You’re swapping heavily. Performance will feel like walking through wet cement.
Decision: Reduce parallel builds, close runaway processes, or tune WSL resource limits. If it happens daily, fix the cause, not the symptom.
Task 13: Identify large directories that poison indexing (usually node_modules or build outputs)
cr0x@server:~$ du -h -d 1 . | sort -h | tail
120M ./dist
1.4G ./node_modules
2.1G .
What it means: Indexing and watching will be expensive if your editor treats these as source.
Decision: Add excludes in VS Code settings and tool configs; consider using package manager options that reduce churn.
Task 14: Confirm port binding behavior (is the service reachable?)
cr0x@server:~$ ss -lntp | head
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.1:3000 0.0.0.0:* users:(("node",pid=14222,fd=20))
LISTEN 0 4096 0.0.0.0:5432 0.0.0.0:* users:(("postgres",pid=981,fd=5))
What it means: Your dev server is bound to loopback only (127.0.0.1). That’s fine if you access it from the same namespace.
Decision: If Windows can’t reach it, bind to 0.0.0.0 where appropriate or use the Remote port forwarding features.
Task 15: Validate DNS and connectivity from inside WSL
cr0x@server:~$ getent hosts github.com | head -n 1
140.82.114.4 github.com
cr0x@server:~$ ping -c 1 github.com
PING github.com (140.82.114.4) 56(84) bytes of data.
64 bytes from 140.82.114.4: icmp_seq=1 ttl=49 time=18.2 ms
--- github.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
What it means: DNS and outbound connectivity work.
Decision: If DNS is flaky, focus on WSL network config and corporate VPN split-tunnel policies rather than blaming VS Code.
Task 16: Check SSH agent situation (avoid password prompts every 3 minutes)
cr0x@server:~$ ssh-add -l
The agent has no identities.
What it means: No keys loaded. You’ll get prompted, or Git operations will fail.
Decision: Load keys into an agent in WSL or use a Windows agent bridged carefully. The safe move is: keep SSH keys and agent inside WSL for WSL repos.
Task 17: Confirm file descriptor limits (rare, but real in big tooling)
cr0x@server:~$ ulimit -n
1024
What it means: Low FD limit can break large watchers, build tools, or test runners.
Decision: If you see “too many open files,” raise it via shell limits and/or system configuration (carefully, and with team guidance).
Fast diagnosis playbook
When Remote WSL feels sluggish or broken, don’t wander. Run a tight loop that identifies the bottleneck class quickly.
First: prove where the repo lives and where tools run
- In the WSL terminal inside VS Code:
pwdandmount | grep /mnt/c. - If your repo is under
/mnt/c, assume filesystem overhead until proven otherwise. - Confirm you are using Linux toolchains:
which git,which node,which python.
Second: check watcher health and indexing pressure
- Look at server logs for
ENOSPCor watcher failures. - Check
/proc/sys/fs/inotify/max_user_watches. - Measure repo bloat:
du -h -d 1 . | sort -h | tailand decide what to exclude.
Third: check CPU, memory, and swap
ps aux --sort=-%cpu | headto catch runaway watchers and compilers.free -hto spot swap thrash.- If memory is tight, reduce concurrency, kill the offender, and then tune WSL resources as a policy—not as a ritual.
Fourth: check networking only after the above
ss -lntpfor port binding truth.getent hostsfor DNS sanity.- Only then touch firewall/VPN settings—otherwise you’ll “fix” the wrong layer and break something else.
Joke #2: If your first debugging step is reinstalling VS Code, you’re not troubleshooting—you’re performing an exorcism.
Common mistakes: symptom → root cause → fix
1) “Everything is slow, especially npm install / git status / TypeScript indexing”
Symptom: Commands that touch many files crawl; fans spin; VS Code feels sticky.
Root cause: Repo lives on /mnt/c (drvfs) while tools run in WSL.
Fix: Move the repo to /home/<you>/src, re-clone if needed, reopen via Remote WSL.
2) “VS Code can’t watch files; changes don’t trigger rebuild; logs show ENOSPC”
Symptom: Auto-reload stops, tests don’t rerun, extension host warns about watchers.
Root cause: inotify watch limits too low for repo size.
Fix: Increase fs.inotify.max_user_watches and max_user_instances (Task 10), then restart.
3) “Git keeps showing massive diffs, or files flip line endings”
Symptom: Every commit includes unrelated changes; teammates argue about CRLF.
Root cause: Mixed Git configurations across Windows and WSL; missing .gitattributes.
Fix: Standardize on LF in repo with .gitattributes; use Linux Git in WSL; set core.autocrlf=input (or false) for WSL workflows.
4) “Remote WSL keeps disconnecting or gets stuck ‘Installing VS Code Server’”
Symptom: Reconnect loops; server install never completes.
Root cause: Disk full, permission issues in home directory, or a corrupted server install.
Fix: Check df -h, review logs under ~/.vscode-server/.cli/logs, and remove the problematic server version directory to force reinstall.
5) “Ports work in WSL but not from Windows browser”
Symptom: Service reachable with curl localhost in WSL, but Windows can’t connect.
Root cause: Service bound to 127.0.0.1 inside WSL namespace; port forwarding assumptions wrong.
Fix: Bind to 0.0.0.0 when safe for dev, or use Remote port forwarding features; verify with ss -lntp.
6) “My build uses Windows tools even in WSL”
Symptom: Strange paths; performance swings; binaries in unexpected locations.
Root cause: Windows interop on PATH causes Windows executables to be picked first.
Fix: Verify with which; reorder PATH; be explicit in scripts; consider limiting interop for dev shells.
7) “Docker images disappear depending on where I run commands”
Symptom: docker images differs between terminals; builds redo constantly.
Root cause: Mixing Docker Desktop integration and a separate Docker Engine in WSL.
Fix: Choose one: Desktop-managed context or native engine. Standardize on one per machine and teach the team the decision.
8) “Case-only renames don’t behave; imports fail on CI but not locally”
Symptom: Works on your machine, fails on Linux CI, or vice versa.
Root cause: Case sensitivity mismatch and Git not recording intended rename semantics cleanly.
Fix: Do renames carefully (temp name then final name), ensure CI matches production, and don’t store repos on case-insensitive mounts when you need Linux semantics.
Three corporate mini-stories from the trenches
Incident: the wrong assumption (the repo location “doesn’t matter”)
A team migrating from MacBooks to Windows wanted a “one-weekend” switch. They picked WSL 2, installed VS Code, and declared victory
after the demo app built successfully. The assumption was implicit: “files are files, and storage is storage.”
By Monday afternoon, developers were reporting that git status took forever, test runs were inconsistent, and TypeScript
language services kept timing out. The quick fix attempts started: reinstall extensions, bump Node versions, and toggle random settings.
The result: different failures, same frustration.
The root cause was boring: the repos were cloned into C:\Users\...\src and opened through WSL. So every build tool in Linux
was hammering drvfs with tens of thousands of metadata operations. On a small repo, you might never notice. On a corporate monorepo,
it’s a tax you pay on every keystroke.
The fix was equally boring: move clones into /home, reopen in Remote WSL, and stop running Windows Git against WSL working trees.
Within a day the complaints stopped. Not because of magic. Because the tools were finally operating on the filesystem they were designed for.
Optimization that backfired: “Let’s speed it up by sharing node_modules on Windows”
Another group tried to get clever with caching. Their Windows laptops had plenty of storage, and they wanted to avoid repeated installs in WSL.
The idea: keep node_modules on the Windows side and bind-mount or symlink it into WSL projects. One install, multiple projects,
fewer downloads. Everyone loves fewer downloads.
For about two days, it looked like a win. Installs were faster—at least on the first run. Then the weirdness arrived: native modules failed to
build, binaries had the wrong ABI expectations, and “works on my machine” became “works until I reboot.” File watching got worse, not better.
The hidden problem was that they optimized the wrong constraint. The bottleneck wasn’t downloading packages; it was filesystem churn and cross-OS
semantics. Node’s ecosystem does a lot of tiny file operations and expects POSIX-like behavior. Putting the hottest directories on drvfs invited
weird edge cases and permanent performance debt.
They rolled it back and adopted a clean rule: dependencies live with the project in ext4, caches are allowed but must be WSL-native, and the team
uses a real registry mirror only if network is the pain point. Their builds became predictable again, which is the kind of “fast” you can schedule around.
Boring but correct practice that saved the day: standardizing the dev baseline
A platform team supporting multiple product teams had a different kind of problem: not performance, but inconsistency. Everyone’s WSL distro had
drifted. Different Ubuntu versions, different system packages, different Git settings. Debugging tickets were basically archaeology.
They did the unsexy work: a baseline checklist and a one-time bootstrap script. It verified WSL 2, ensured repos lived in /home, set
inotify limits, pinned a small set of toolchain versions, and printed clear outputs when something didn’t match. No fancy UI. Just disciplined defaults.
Weeks later, a Windows update triggered a wave of “Remote WSL disconnected” reports. The teams following the baseline recovered in minutes because
they had known-good checkpoints: disk free, server logs path, and a small set of config files to compare. The teams without it lost half a day
each trying random forum fixes.
The practice wasn’t glamorous. It didn’t win anyone a performance trophy. But it reduced mean time to sanity, which is what production-minded
engineering is actually about.
Checklists / step-by-step plan
Checklist A: The “native feel” baseline (do this once per machine)
- Confirm WSL 2:
wsl.exe -l -vshows VERSION 2 for your distro. - Update packages in WSL and install core tooling (git, build essentials, language toolchains).
- Create a sane workspace directory:
~/srcand clone repos there. - Open VS Code via Remote WSL by running
code .from inside the repo in WSL. - Raise inotify limits (especially for JS/TS, monorepos): set sysctl values and apply them.
- Set Git policy: choose LF and enforce with
.gitattributes; ensure WSL Git is used for WSL repos. - Decide Docker model: Desktop integration or native engine—pick one and document it for your future self.
- Exclude junk directories in VS Code settings: build outputs, dependency folders, tool caches as appropriate.
- Verify SSH works: ensure keys and agent are available in WSL for Git operations.
Checklist B: New repo onboarding (per project)
- Clone into
~/srcin WSL. - Open with
code .(from WSL) so VS Code attaches correctly. - Run the project’s bootstrap command and watch for file watcher warnings.
- Check port exposure with
ss -lntpand decide whether it should bind to 127.0.0.1 or 0.0.0.0. - Check disk usage after dependency install (
df -h,du) and decide if you need cleanup rules.
Checklist C: When it suddenly gets slow (10-minute triage)
- Is the repo under
/mnt/c? If yes, stop and move it. - Do logs show
ENOSPC? If yes, raise inotify limits. - Is CPU pegged when idle? Identify the process and determine if it’s polling or legitimate work.
- Is swap heavily used? Reduce concurrency and kill runaway processes; then tune resources.
- Only then: check networking and VPN constraints.
FAQ
1) Should I store my repos in Windows and just use WSL tools?
No for anything non-trivial. It’s the number-one cause of “WSL is slow” reports. Put repos in WSL’s Linux filesystem and open them via Remote WSL.
2) Is WSL 2 always better than WSL 1 for VS Code Remote?
For modern dev stacks, yes. WSL 2’s real kernel improves compatibility and tooling behavior. WSL 1 can be okay for certain I/O patterns, but it’s the exception now.
3) Why does VS Code install something inside WSL?
Because Remote WSL runs a VS Code Server in the Linux environment. That server hosts extensions and language tooling close to your code and toolchain.
4) My extension works in Windows but not in WSL. Is that a bug?
Sometimes it’s simply the wrong execution side. Some extensions need to run where the filesystem and tools are. Prefer extensions that support remote execution cleanly.
5) How do I stop file watchers from melting my CPU?
First, raise inotify limits if you hit ENOSPC. Second, exclude build outputs and dependency directories from watching/indexing. Third, check if a tool is polling.
6) What’s the best approach for SSH keys: Windows agent or WSL agent?
For WSL repos, keep keys and an agent inside WSL. It reduces cross-boundary weirdness. If corporate policy requires Windows-managed keys, bridge deliberately and test it.
7) Why can’t Windows reach my WSL service on localhost?
Usually because the service is bound to 127.0.0.1 inside WSL, or port forwarding is not set up the way you think. Verify with ss -lntp and bind appropriately.
8) Can I use Docker inside WSL without Docker Desktop?
Yes, you can run Docker Engine in WSL. The key is consistency: don’t mix that with Docker Desktop contexts unless you enjoy chasing phantom caches.
9) Why does Git behave differently between Windows and WSL?
Differences include line endings, file mode bits, and case sensitivity assumptions. Pick one Git environment for a repo (WSL Git for WSL repos) and enforce policy via .gitattributes.
10) What’s the single best “native feel” improvement?
Move the repo into WSL’s Linux filesystem. Everything else is tuning around that foundational decision.
Conclusion: practical next steps
If you want Remote WSL to feel native, stop treating it like a novelty and start treating it like a workstation with a topology. Put code where Linux tools are fast.
Run tooling where the filesystem semantics match. Set watcher limits like you mean it. And when something breaks, measure first.
Next steps you can do today:
- Create
~/srcin WSL and re-clone one medium-sized repo there. - Open it with
code .from WSL and verifywhich gitandpwd. - Raise inotify limits preemptively if you have a large repo or JS toolchain.
- Run the fast diagnosis playbook once when things are “good” so you know what normal looks like.
The payoff is not just speed. It’s predictability. And predictability is what lets you ship without turning your laptop into a second job.