How --set-sparse saved 25 GB on my C: drive (and why almost nobody knows about it)
DevOps

How --set-sparse saved 25 GB on my C: drive (and why almost nobody knows about it)

September 11, 2026

Last week I opened the Windows Storage settings and noticed something weird: my C: partition was sitting at 100%, with only a handful of gigabytes free. I hadn't installed anything huge. No games, no video files, no big database migrations. The only thing I'd been doing for the previous weeks was running a vLLM server inside WSL2.

A quick dir on AppData pointed at the culprit right away:

C:\Users\<me>\AppData\Local\WSL\Ubuntu\ext4.vhdx    55.02 GB

55 GB. For an Ubuntu install that, by all internal accounts, only held about 30 GB of real data.

The mystery

WSL2 stores each Linux distribution inside a single virtual hard disk file (ext4.vhdx) on the Windows side. That file is supposed to be sparse: the distro thinks it has a 250 GB disk available, while the host file only consumes physical bytes for the data actually written to it. Writes go in, blocks get allocated; deletes plus a periodic fstrim should release them back to the host.

That's the theory. In practice, WSL2 ships the VHDX as a fully-provisioned file, not a true NTFS sparse one. You can confirm it with one command:

> fsutil sparse queryflag "$env:LOCALAPPDATA\WSL\Ubuntu\ext4.vhdx"
This file is NOT set as sparse

Without the sparse flag, every byte ever written to the VHDX stays allocated on the Windows side forever—even after the corresponding file is deleted inside Linux. The VHDX grows, but it never shrinks.

That explained my numbers exactly: df -h inside the distro reported 29 GB used, but the host file was 55 GB. There were ~26 GB of free space inside the Linux filesystem that had become permanently pinned in the VHDX.

The fix: --set-sparse true

WSL has a flag for this. It's been sitting in wsl --help since 2024, but it's not exactly advertised:

wsl --shutdown
wsl --manage Ubuntu --set-sparse true --allow-unsafe

Two things to notice here:

  1. --allow-unsafe is mandatory. Microsoft disables the flag by default because of an old data-corruption bug in early WSL2 builds. Modern WSL2 doesn't have that bug, but the safety latch is still on. If you forget --allow-unsafe you'll get a polite refusal about “potential data corruption”—it's not a permissions thing, just a Microsoft policy.
  2. You may need wsl --shutdown first. If the distro is running, wsl --manage returns ERROR_SHARING_VIOLATION and tells you to shut it down. Re-run after the shutdown.

After this, the VHDX is a real NTFS sparse file:

> fsutil sparse queryflag "$env:LOCALAPPDATA\WSL\Ubuntu\ext4.vhdx"
This file is set as sparse  ✓

The WSL-native reclaim path: fstrim

Once sparse is on, the WSL-native way to release unused space is the same one Linux has used for a decade:

sudo fstrim -v /
# /: 222.1 GiB (238447005696 bytes) trimmed

That tells the kernel “these ext4 blocks are free”, and the VHDX driver hands those hints back to NTFS, which deallocates them from the host file. No shutdown of the distro, no admin elevation, no scheduled task—just an in-place operation.

A few things worth knowing if you're going to rely on this:

  • Ubuntu's weekly fstrim.timer doesn't fire inside WSL by default. systemd ships it with ConditionVirtualization=!container, and WSL2 reports itself as a container. You have to invoke fstrim manually, or override the timer with systemctl edit fstrim.timer. I prefer manual, so I leave it alone.
  • wsl --manage <Distro> --compact does not work once sparse is on. It fails with “Virtual hard disk files ... must not be sparse”—that's a Hyper-V API constraint, not a WSL bug. You don't need --compact anyway once sparse mode is on, because the file tracks your data automatically.
  • diskpart compact vdisk works, but it forces the VHDX back into non-sparse mode. You'd then have to re-enable sparse after. It's the legacy approach. Pick one path or the other; don't mix.

Putting it in a one-liner

I keep this in ~/Scripts/compact-wsl.ps1 and call it whenever I want peace of mind:

$vhdx = "$env:LOCALAPPDATA\WSL\Ubuntu\ext4.vhdx"
$before = (Get-Item $vhdx).Length
wsl -d Ubuntu -- bash -c 'sudo fstrim -v /'
$after = (Get-Item $vhdx).Length
"{0:N2} GB -> {1:N2} GB ({2:N1} GB reclaimed)" -f `
    $before/1GB, $after/1GB, ($before-$after)/1GB

No shutdown. No admin. No scheduled task. Just a thin wrapper around the WSL-native reclaim path.

Results

Here's what actually happened on my machine:

StepVHDX size
Before any change55.02 GB
After one wsl --manage Ubuntu --compact32.4 GB
After enabling sparse mode30.26 GB
Wrote 40 GB inside WSL, deleted, fstrim30.26 GB

The file stopped growing the moment sparse mode went on. Writing 40 GB of test data and deleting it didn't move the needle, because NTFS was already holding ~250 GB of virtual space “for free” through the sparse flag—and fstrim was happily returning blocks to the host as I deleted files.

TL;DR

  • WSL2 VHDX files grow on the host but don't shrink unless they're true NTFS sparse files.
  • Check: fsutil sparse queryflag <path>.
  • One-time fix: wsl --shutdown && wsl --manage <Distro> --set-sparse true --allow-unsafe.
  • Day-to-day reclaim: sudo fstrim -v / inside the distro. No shutdown, no admin.
  • Don't bother with diskpart or wsl --manage --compact once sparse is on—they're mutually exclusive with it.

One flag, one fstrim, and 25 GB back on your C: drive.


If you found this useful and want to read the actual digging that led to it: I noticed the gap when my C: drive hit 100% during a routine vLLM session. There was no error, no warning—just an OS quietly running out of space because of a default that should have been the other way around.

WSL2 Windows DevOps Disk space