Skip to content
WSLDeep Dive Published Updated 5 min readViews unavailable

How WSL Bridges Two Completely Different Filesystems

WSL's cross-OS file access translates between Linux and Windows filesystem semantics at the protocol level, and that translation has a real performance cost.

Being able to run explorer.exe . from a Linux shell and have Windows Explorer open the current Linux directory feels seamless — underneath, it’s bridging two filesystems with genuinely different semantics, and that bridging isn’t free.

The two directions of access, and why they’re not symmetric

Accessing Windows files from Linux (via /mnt/c/...) and accessing Linux files from Windows (via the \\wsl$\ network path) are implemented differently, and perform differently, because the “native” filesystem on each side has fundamentally different characteristics the other side has to accommodate.

Why Linux-native files perform better than /mnt/c access

WSL2’s Linux filesystem lives inside the lightweight VM on a virtual disk formatted as ext4 — genuinely native Linux filesystem performance for anything staying within that Linux-side filesystem. Accessing Windows files from /mnt/c instead goes through DrvFs, which Microsoft built on top of a Plan 9 (9P) file server running on the Windows side, communicating over a Hyper-V socket connection to the Linux side, adding real per-operation overhead compared to native ext4 access.

Why this specific direction is slower, concretely

Every file operation crossing from Linux to /mnt/c has to translate Linux filesystem semantics (permissions bits, symlinks, case-sensitive filenames) into NTFS’s different semantics, serialized as 9P protocol messages bounded by a fixed message-size parameter, over the Hyper-V socket connection to the Windows host — for workloads doing large numbers of small file operations (like node_modules-heavy JavaScript projects), this per-message overhead compounds into a genuinely noticeable slowdown compared to keeping the same project entirely on the Linux-native filesystem.

virtiofs: a newer, faster transport for the same bridge

Because 9P’s message-based protocol overhead is the specific bottleneck for metadata-heavy workloads, Microsoft added an alternative transport called virtiofs, using the VirtIO shared-memory transport instead of 9P’s serialized messaging — reducing the per-operation overhead considerably for exactly the small-file-heavy access patterns that suffer most under 9P. It remains opt-in rather than the default:

# %UserProfile%\.wslconfig
[wsl2]
virtiofs=true

As with most .wslconfig changes, this requires wsl --shutdown and a restart to take effect. Because it’s newer and opt-in, confirm your installed WSL version actually supports it before assuming the setting will do anything, and benchmark your own actual workload rather than assuming virtiofs is strictly better for every use case — 9P’s read performance is already solid for many workloads, with the more pronounced gains from virtiofs showing up specifically in write-heavy and small-file-heavy scenarios.

The other direction: accessing WSL files from Windows

Windows accesses WSL2’s Linux filesystem through the \\wsl$\ (or newer \\wsl.localhost\) network path, which Windows treats similarly to any other network share — convenient for occasionally reaching into a Linux project from Windows tools, but not the path you’d want for sustained, intensive file operations from the Windows side either.

The practical rule this leads to

The consistent, practical guidance from Microsoft’s own WSL documentation is: keep a project’s files on the filesystem matching whichever OS’s tools you’re using most intensively — a Node.js or Python project you’re actively building and running from the Linux side belongs on the Linux-native filesystem (~/projects/, not /mnt/c/Users/.../projects/), even if you occasionally open individual files from Windows-side tools.

Why case sensitivity is a frequent, specific gotcha

Linux filesystems are case-sensitive by default (File.txt and file.txt are different files); NTFS is case-insensitive by default. This mismatch occasionally surfaces as confusing behavior — a Linux tool creating two files that Windows sees as a naming conflict, or a Windows-side tool failing to find a file due to a case mismatch that Linux tooling wouldn’t have cared about.

Why understanding this bridge matters beyond just performance

Beyond raw speed, understanding that /mnt/c and \\wsl$\ are genuinely different access paths, going through genuinely different translation layers, explains a range of WSL behavior that otherwise looks inconsistent — from performance differences to permission-bit oddities to occasional case-sensitivity surprises, all tracing back to the same underlying reality: two different filesystems, with different rules, being bridged rather than unified.

Measuring the actual gap on your own machine

General guidance about “keep Linux projects on the Linux filesystem” is worth confirming concretely rather than taking entirely on faith. Timing an identical operation — cloning a moderately-sized repository, or running an incremental build — from both ~/projects and /mnt/c/projects gives a direct, machine-specific measurement of how much the crossing actually costs for your specific hardware and workload, which is more convincing (and occasionally more surprising) than a generic percentage figure from someone else’s benchmark.

What this means for editors and IDEs specifically

A Windows-native editor or IDE opening a project that lives on the Linux-native filesystem has to reach it through \\wsl.localhost, paying that direction’s translation cost for every file it reads — including the potentially large number of files a modern IDE’s indexing and search features scan on startup. Many popular editors address this with a WSL-aware remote mode (running the actual editor server process inside the distribution itself, with only the UI communicating across the boundary) specifically to avoid this cost; confirming your editor is using that mode, rather than opening the project as if it were an ordinary Windows-side folder, matters as much for editor responsiveness as filesystem placement does for build performance.

Why this bridge exists at all rather than a unified filesystem

Building a single, unified filesystem that natively satisfied both Linux’s and NTFS’s semantics simultaneously would mean picking one side’s rules and forcing the other to approximate them, likely poorly for whichever side lost out. Bridging two genuinely native filesystems, each behaving correctly according to its own rules, and translating deliberately at the boundary, is the more honest engineering trade-off — it makes the cost of crossing that boundary visible and measurable, rather than hiding an approximation that would eventually surface as its own, harder-to-diagnose category of bugs.

Related:

Sources:

Comments