If you develop on Windows with WSL2 long enough, you’ll eventually notice your Linux disk file growing: the ext4.vhdx keeps expanding as you install packages, build projects, pull Docker images, and delete them. But unlike a native filesystem, deleting files doesn’t automatically return space to Windows. This guide shows you exactly How to Shrink and Compact ext4.vhdx Without Data Loss so you can reclaim tens (sometimes hundreds) of gigabytes safely. You’ll learn why the issue happens, what prerequisites you need, multiple ways to compact, how to keep it from growing unnecessarily, and how to troubleshoot related performance issues.
H2: Overview
The core of the problem: In WSL2, each distro lives inside a virtual disk file named ext4.vhdx. It expands as data is written. When you delete data inside the Linux filesystem, the file’s size on Windows does not automatically shrink. That’s normal for thin-provisioned virtual disks. The fix is a two-part process:
- Inside WSL: Mark free space as reclaimable (e.g., via fstrim).
- On Windows: Run a compaction tool that reclaims the free blocks from the VHDX.
Typical scenarios where you’ll need this:
- You frequently build large projects (Node.js, Java, C/C++) and caches explode in size.
- You use Docker with the WSL2 backend; pulling/pruning images and containers balloons docker-desktop-data.
- You installed big SDKs or datasets, then deleted them.
- You imported/exported distros and saw the file size jump.
This guide covers the recommended approach with fstrim + Optimize-VHD, a Docker-specific path, and a fully safe export/import method—along with newer WSL features that can help with automatic reclamation.
H2: Quick Reference Table
| Command | Purpose | Example Output |
|---|---|---|
| wsl –status | Show WSL version and kernel info | Default Distribution: Ubuntu; Kernel version: 5.15.xx |
| wsl -l -v | List distros and versions | NAME STATE VERSION; Ubuntu Running 2 |
| wsl –update | Update WSL (Store version) | Checking for updates… The operation completed successfully. |
| sudo fstrim -av | Mark free space as discardable (TRIM) | /: 12.4 GiB (13330321408 bytes) trimmed |
| wsl –shutdown | Stop all WSL VMs so the VHDX is unlocked | (no output) |
| Optimize-VHD -Path “C:…\ext4.vhdx” -Mode Full | Windows-side compaction of the VHDX | Progress bar or no output if run in script |
| diskpart → select vdisk file=… → compact vdisk | Alternative compaction (varies by system) | DiskPart successfully compacted the virtual disk file. |
| wsl –export Distro C:\path\backup.tar | Safe backup/export of a distro | Export in progress… |
| wsl –import NewDistro C:\path\NewDir C:\path\backup.tar –version 2 | Re-import to a fresh VHDX | Importing… |
| docker system prune -a | Remove unused Docker data | Total reclaimed space: 15.2GB |
Note: Optimize-VHD is part of the Hyper-V PowerShell module (Management Tools). Prefer Optimize-VHD over diskpart for VHDX. If diskpart compact doesn’t work on your system, use Optimize-VHD.
H2: Key Concepts & Prerequisites
H3: What you need
- Windows 10 2004 or later, or Windows 11. Windows 11 with the Microsoft Store version of WSL is recommended.
- WSL2 distros (check with wsl -l -v).
- Administrative rights on Windows to run compaction commands and enable features.
- Optional but recommended: Hyper-V PowerShell module (Management Tools only) to get Optimize-VHD.
- Turn Windows features on or off → Hyper-V → check “Hyper-V Management Tools” (you do NOT need “Hyper-V Platform” to use the PowerShell module).
- Sufficient free space to create a backup copy of the VHDX before compacting (strongly recommended).
- Basic command-line familiarity on both Windows PowerShell and Linux.
H3: Where to find ext4.vhdx
- Store-installed distros: %LOCALAPPDATA%\Packages\
\LocalState\ext4.vhdx - Imported distros: wherever you chose as the install directory.
- Docker Desktop data: %LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx (or a similar path under the Docker package).
H3: Why fstrim matters
fstrim tells the filesystem to discard blocks that are no longer used. Without this, the Windows compactor won’t know which blocks can be reclaimed and your ext4.vhdx won’t shrink much (or at all).
H3: Safety first
Compaction is safe when done correctly, but always:
- Make a backup of ext4.vhdx before you start.
- Ensure WSL is fully shut down to release the file lock (wsl –shutdown).
- Avoid interruptions during compaction.
H2: Step-by-Step Guide
H3: 1) Verify your WSL status and version
Run these on Windows PowerShell:
wsl –status
wsl -l -v
wsl –update
- Confirm your distro is on Version 2.
- Update WSL so you have the latest features and bug fixes.
H3: 2) Free up space inside your distro
Open your WSL distro and remove unused data:
- Package caches and logs:
sudo apt-get clean
sudo apt-get autoremove -y
sudo journalctl –vacuum-time=7d
- Language/package managers:
npm cache clean –force
yarn cache clean
pip cache purge
- Docker (if using Docker in WSL):
docker system prune -a
docker volume prune
docker builder prune -a
- Find large folders/files:
sudo du -xh / | sort -h | tail -n 50
Remove what you don’t need.
H3: 3) TRIM free space with fstrim
In your WSL distro:
sudo fstrim -av
You should see output like:
/: 12.4 GiB (13330321408 bytes) trimmed
If fstrim isn’t available or doesn’t reclaim much space, you can zero-fill as a fallback (slower):
sudo dd if=/dev/zero of=~/zero.fill bs=64M || true
sync
rm ~/zero.fill
sync
Then run fstrim again:
sudo fstrim -av
H3: 4) Shut WSL down
Back in Windows PowerShell:
wsl –shutdown
Wait a few seconds. Ensure no Linux processes remain (e.g., vmmem should disappear in Task Manager).
H3: 5) Back up ext4.vhdx
Strongly recommended before compaction. Example:
Copy-Item “$env:LOCALAPPDATA\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\ext4.vhdx” `
“$env:USERPROFILE\Desktop\ext4-backup-$(Get-Date -Format yyyyMMdd-HHmm).vhdx”
Adjust the path for your distro. If you are unsure of the path, search:
Get-ChildItem “$env:LOCALAPPDATA\Packages” -Directory |
Where-Object { $.Name -match “Ubuntu|Debian|openSUSE|kali|Arch” } |
ForEach-Object {
$vhd = Join-Path $.FullName “LocalState\ext4.vhdx”
if (Test-Path $vhd) { “$($_.Name) => $vhd” }
}
H3: 6) Compact the VHDX on Windows (recommended: Optimize-VHD)
Load the Hyper-V module and run Optimize-VHD:
Import-Module Hyper-V
Optimize-VHD -Path “C:\Users\
-Mode Full is thorough; -Mode Quick is faster but may reclaim less.
If you can’t install the Hyper-V module, try DiskPart (works on many systems):
diskpart
select vdisk file=”C:\Users\
compact vdisk
exit
Note: DiskPart’s compact support for VHDX can vary. If it fails or reports no change, use Optimize-VHD.
H3: 7) Start WSL again and verify
Start your distro:
wsl -d
Check everything is intact (files, tools). Confirm the file size shrank:
Get-Item “C:\Users\
Compare Length to your backup copy or the size observed before compaction.
H3: 8) Optional: Compact Docker’s docker-desktop-data
Docker Desktop’s WSL2 backend stores images and layers in its own ext4.vhdx. To reclaim space:
- In Docker Desktop: Settings → Resources → WSL Integration: disable temporarily, then exit Docker Desktop.
- Free space within Docker (inside your Linux shell) first:
docker system prune -a
docker volume prune
docker builder prune -a
- Shut down WSL:
wsl –shutdown
- Compact the Docker vhdx (path may vary; common paths shown):
Optimize-VHD -Path “$env:LOCALAPPDATA\Docker\wsl\data\ext4.vhdx” -Mode Full
- Restart Docker Desktop.
H3: 9) Alternative, bulletproof method: export, re-import (new, smaller VHDX)
If Optimize-VHD isn’t available or didn’t shrink enough, exporting and re-importing compresses your distro to exactly what’s used.
- Export (safe backup):
wsl –export Ubuntu C:\WSL\Backups\Ubuntu-$(Get-Date -Format yyyyMMdd).tar
- Import to a new distro name:
wsl –import Ubuntu-compact C:\WSL\Ubuntu-compact C:\WSL\Backups\Ubuntu-20250101.tar –version 2
- Test the new distro:
wsl -d Ubuntu-compact
- If everything is good, you may switch and remove the old one:
wsl –unregister Ubuntu
Note: For Canonical Ubuntu appx, set default user if needed:
ubuntu config –default-user
Or create /etc/wsl.conf in the new distro to set the default user.
H2: Troubleshooting
H3: DNS not working inside WSL2
Symptoms: apt update fails to resolve, curl can’t resolve host.
Fix 1: Regenerate resolv.conf
- Ensure WSL manages resolv.conf:
sudo rm /etc/resolv.conf
echo “[network]” | sudo tee /etc/wsl.conf
echo “generateResolvConf = true” | sudo tee -a /etc/wsl.conf
wsl –shutdown
Reopen WSL and test.
Fix 2: Set static DNS servers
- Prevent auto-gen and set your own:
echo “[network]” | sudo tee /etc/wsl.conf
echo “generateResolvConf = false” | sudo tee -a /etc/wsl.conf
sudo rm /etc/resolv.conf
echo “nameserver 1.1.1.1” | sudo tee /etc/resolv.conf
echo “nameserver 8.8.8.8” | sudo tee -a /etc/resolv.conf
wsl –shutdown
Fix 3: In .wslconfig
- If corporate VPN/DNS is complex, try disabling DNS proxy:
In Windows at %UserProfile%.wslconfig:
[wsl2]
dnsProxy=false
Then:
wsl –shutdown
H3: Git is slow on WSL2
- Avoid working in /mnt/c. Keep repos in the Linux filesystem (e.g., ~/code).
- Enable Git file system cache:
git config –global core.fscache true
- Disable executable bit changes if not needed:
git config –global core.fileMode false
- If antivirus is scanning, exclude your project directory or the VHDX file (security trade-off; consult your org’s policy).
H3: Disk space keeps bloating
- Clean caches regularly:
sudo apt-get clean && sudo apt-get autoremove -y
npm cache clean –force
yarn cache clean
pip cache purge
docker system prune -a
- TRIM and compact periodically:
sudo fstrim -av
wsl –shutdown
Optimize-VHD -Path “…\ext4.vhdx” -Mode Full
- Consider export/import if compaction stalls.
H3: File I/O slowness
- Keep active projects in the Linux filesystem, not on /mnt/c.
- Use WSLg/Plan9 file sharing sparingly for hot paths.
- Exclude heavy dev folders from real-time antivirus scans (evaluate risk).
- Tune WSL resources (.wslconfig) to reduce swapping and contention.
H2: Optimization & Best Practices
H3: Configure .wslconfig for better resource usage
Create or edit %UserProfile%.wslconfig on Windows:
[wsl2]
memory=6GB
processors=4
swap=0
localhostForwarding=true
pageReporting=true
autoMemoryReclaim=gradual
Requires recent WSL (Store) builds:
sparseVhd=true
- memory: Cap VM RAM to prevent runaway use.
- processors: Set CPU cores for balance.
- swap=0: Reduces host disk churn; if you need swap, set a small file instead.
- pageReporting and autoMemoryReclaim: Encourage WSL to return memory to Windows.
- sparseVhd=true: Enables automatic sparse trimming of the VHD where supported, helping keep ext4.vhdx from bloating.
After changes:
wsl –shutdown
H3: Keep Docker layers under control
- Prune regularly:
docker system prune -a
docker volume prune
docker builder prune -a
- Use multi-stage builds and .dockerignore to minimize layer size.
- Place Docker bind mounts inside the Linux filesystem for speed.
H3: Work in the right filesystem
- Put your source code, node_modules, and build artifacts in the Linux filesystem (e.g., /home/you/project). Accessing /mnt/c can be much slower and can exacerbate disk bloat.
H3: Automate housekeeping
- Add a weekly scheduled task on Windows that runs:
wsl.exe -e /usr/sbin/fstrim -av
wsl.exe –shutdown
PowerShell -NoProfile -Command “Import-Module Hyper-V; Optimize-VHD -Path ‘C:…\ext4.vhdx’ -Mode Quick”
- Or trigger it after large CI-like builds.
H3: Backups and exports
- Use wsl –export to back up distros before major changes. Export/import doubles as a defragment/compact operation.
H2: Project-Based Example: Speeding Up a Node.js Monorepo and Reclaiming 30+ GB
Scenario: You run a large Node.js monorepo (pnpm + TurboRepo) on WSL2 with Docker. Builds are heavy and frequent. Disk usage soared; Docker images accumulate, and the ext4.vhdx is 70+ GB.
Step 1: Move your project into Linux filesystem
- Clone into ~/work/monorepo instead of /mnt/c/Users/you/monorepo. This immediately improves I/O performance.
Step 2: Clean caches and logs inside WSL
- Node and package caches:
pnpm store prune
npm cache clean –force
yarn cache clean
- Build artifacts:
rm -rf dist .turbo node_modules/.cache
- System packages:
sudo apt-get clean && sudo apt-get autoremove -y
Step 3: Trim Docker data
- Remove stale images, containers, and builders:
docker system prune -a
docker volume prune
docker builder prune -a
Step 4: fstrim the filesystem
sudo fstrim -av
Expect to see several gigabytes trimmed.
Step 5: Shut down WSL
wsl –shutdown
Step 6: Compact both your distro and Docker’s data
- Optimize your primary distro VHDX:
Optimize-VHD -Path “C:\Users\you\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_…\LocalState\ext4.vhdx” -Mode Full
- Optimize Docker’s VHDX:
Optimize-VHD -Path “$env:LOCALAPPDATA\Docker\wsl\data\ext4.vhdx” -Mode Full
Step 7: Add .wslconfig tuning
Create/edit %UserProfile%.wslconfig:
[wsl2]
memory=8GB
processors=8
swap=0
pageReporting=true
autoMemoryReclaim=gradual
sparseVhd=true
Step 8: Validate improvements
- Confirm ext4.vhdx sizes dropped significantly.
- Run pnpm install and TurboRepo builds from the Linux filesystem; verify improved cold and warm build times.
- Observe lower memory pressure and faster I/O overall.
Optional: If Optimize-VHD fails to reclaim enough space, perform export/import to a new distro name and switch once validated.
H2: Conclusion
You now know exactly How to Shrink and Compact ext4.vhdx Without Data Loss on WSL2. The process is straightforward: Clean up inside Linux, run fstrim to mark free space, shut down WSL, then compact the VHDX from Windows—preferably with Optimize-VHD. If needed, export/import gives you a fresh, right-sized virtual disk. Add .wslconfig optimizations (including sparseVhd where supported), keep Docker layers tidy, and work from the Linux filesystem to avoid I/O pitfalls. With these practices, WSL2 stays fast, lean, and reliable for everyday development.
H2: FAQ
H4: Does compacting ext4.vhdx risk my data?
Compaction is safe when done correctly. Always back up the ext4.vhdx file before you start. Ensure WSL is fully shut down (wsl –shutdown) and avoid interrupting Optimize-VHD or diskpart while they’re running.
H4: I don’t have the Hyper-V PowerShell module. Can I still shrink?
Yes. Try diskpart’s “compact vdisk.” If that doesn’t shrink VHDX on your system, use the export/import method (wsl –export … then wsl –import …). Export/import always creates a clean, right-sized VHDX.
H4: Why did fstrim not report much reclaimed space?
Perhaps there isn’t much free space to reclaim, or files were recently zeroed but not truly freed (e.g., moved to trash-like locations). Clean caches (apt/npm/docker/etc.), remove big artifacts, run fstrim again, then compact from Windows. As a last resort, try the zero-fill trick before rerunning fstrim.
H4: Can I shrink Docker’s WSL2 data too?
Yes. Prune Docker data, run fstrim, shut down WSL, then compact the Docker data VHDX (often under %LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx). Doing both your distro and Docker’s VHDX often yields major space savings.
H4: How do I keep ext4.vhdx from growing so fast?
- Keep repos in the Linux filesystem, not /mnt/c.
- Prune Docker regularly.
- Clean package caches.
- Run periodic fstrim and compaction.
- On recent WSL builds, set [wsl2] sparseVhd=true in .wslconfig to help automatic reclamation.
You’ve got this—keep your WSL2 environment lean, fast, and ready for work!
