Overview
Windows Subsystem for Linux (WSL) stores its filesystem in a virtual hard disk file (.vhdx). Over time, this file can grow larger than necessary, consuming disk space even after files are deleted inside WSL. This guide shows you how to:
- Compact the WSL virtual disk to reclaim unused space
- Expand the WSL disk when you need more storage
- Verify disk usage and manage storage efficiently
Prerequisites: Administrator privileges on Windows. Basic familiarity with PowerShell and disk management.
Why Compact WSL Disk?
Common Scenarios
- Deleted large files inside WSL, but disk space wasn't freed
- Removed packages (apt, pip, npm), but
.vhdxfile still large - Temporary files accumulated over time
- Need to free up disk space on your Windows host
How It Works
WSL uses sparse files that grow but don't automatically shrink. The virtual disk file (.vhdx) expands as you add data but doesn't compact when you delete files. Manual compaction is required to reclaim that space.
Finding Your WSL Disk File
Locate WSL Installations
First, find which WSL distributions you have installed:
wsl --list --verbose
Output example:
NAME STATE VERSION
Ubuntu-20.04 Running 2
Ubuntu-22.04 Stopped 2
Debian Stopped 2
Find the .vhdx File Location
WSL 2 virtual disks are stored in:
C:\Users\<YourUsername>\AppData\Local\Packages\<PackageName>\LocalState\ext4.vhdx
Common package names:
- Ubuntu 20.04:
CanonicalGroupLimited.Ubuntu20.04LTS_79rhkp1fndgsc - Ubuntu 22.04:
CanonicalGroupLimited.Ubuntu2204LTS_79rhkp1fndgsc - Debian:
TheDebianProject.DebianGNULinux_76v4gfsz19hv4 - Custom installs: Check
wsl --list --verbosefor exact name
Quick PowerShell Command
# Find all WSL vhdx files
Get-ChildItem -Path $env:LOCALAPPDATA\Packages -Recurse -Filter *.vhdx | Select-Object FullName, @{Name="Size(GB)";Expression={[math]::Round($_.Length / 1GB, 2)}}
Compacting WSL Disk
Important Notes
⚠️ Before compaction:
- Shut down all WSL instances
- Ensure no WSL processes are running
- Back up important data (optional but recommended)
Shut Down WSL
# Shut down all WSL instances
wsl --shutdown
# Verify WSL is stopped (should return nothing)
wsl --list --running
Preparing the Disk
Before compacting, you need to zero out free space inside WSL. This tells the host system which blocks are actually free.
Option 1: Using dd (Recommended)
-
Start WSL:
wsl -d Ubuntu-20.04 -
Zero out free space:
# Create a large file filled with zeros sudo dd if=/dev/zero of=/zero.fill bs=1M status=progress # Wait for completion, then delete the file sudo rm -f /zero.fill -
Exit WSL:
exit
Option 2: Using fallocate (Faster)
# Allocate file using fallocate (much faster)
sudo fallocate -l $(($(df / | tail -1 | awk '{print $4}') * 1024)) /zero.fill
# Remove the file
sudo rm -f /zero.fill
Option 3: Using PowerShell Script (Automated)
Create a script compact-wsl.ps1:
# compact-wsl.ps1
param(
[Parameter(Mandatory=$true)]
[string]$DistroName
)
Write-Host "Shutting down WSL..." -ForegroundColor Yellow
wsl --shutdown
Start-Sleep -Seconds 2
Write-Host "Starting $DistroName..." -ForegroundColor Yellow
wsl -d $DistroName -e bash -c "sudo dd if=/dev/zero of=/zero.fill bs=1M status=progress && sudo rm -f /zero.fill && exit"
Write-Host "Shutting down WSL again..." -ForegroundColor Yellow
wsl --shutdown
Start-Sleep -Seconds 2
$vhdxPath = "$env:LOCALAPPDATA\Packages\$((Get-AppxPackage | Where-Object {$_.Name -like "*$DistroName*"}).PackageFamilyName)\LocalState\ext4.vhdx"
if (Test-Path $vhdxPath) {
Write-Host "Compacting disk at: $vhdxPath" -ForegroundColor Green
Optimize-VHD -Path $vhdxPath -Mode Full
Write-Host "Done!" -ForegroundColor Green
} else {
Write-Host "Error: Could not find vhdx file" -ForegroundColor Red
}
Run it:
.\compact-wsl.ps1 -DistroName "Ubuntu-20.04"
Step-by-Step Compaction
Method 1: Using diskpart (Manual)
-
Open PowerShell as Administrator
-
Start diskpart:
diskpart -
Select your WSL virtual disk:
select vdisk file="C:\Users\YourUsername\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx" -
Attach the disk in read-only mode:
attach vdisk readonly -
Compact the disk:
compact vdisk -
Detach the disk:
detach vdisk -
Exit diskpart:
exit
Method 2: Using PowerShell Optimize-VHD (Recommended)
# Navigate to the vhdx file location
$vhdxPath = "C:\Users\YourUsername\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx"
# Compact the virtual disk (requires Hyper-V module)
Optimize-VHD -Path $vhdxPath -Mode Full
Note: If Optimize-VHD is not available, enable Hyper-V:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
Method 3: One-Liner PowerShell Command
# Find and compact all WSL disks
Get-ChildItem -Path "$env:LOCALAPPDATA\Packages" -Recurse -Filter "ext4.vhdx" | ForEach-Object {
Write-Host "Compacting: $($_.FullName)" -ForegroundColor Yellow
Optimize-VHD -Path $_.FullName -Mode Full
}
Expanding WSL Disk
If you need more space in your WSL distribution, you can expand the virtual disk:
Method 1: Using PowerShell
# Expand to 100GB
$vhdxPath = "C:\Users\YourUsername\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx"
Resize-VHD -Path $vhdxPath -SizeBytes 100GB
Method 2: Using diskpart
diskpart
select vdisk file="C:\Users\YourUsername\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx"
expand vdisk maximum=100000
exit
Resize Filesystem Inside WSL
After expanding the virtual disk, resize the filesystem:
# Start WSL
wsl -d Ubuntu-20.04
# Check current disk size
df -h /
# Resize the filesystem (resize2fs for ext4)
sudo resize2fs /dev/sdb
# Or for newer WSL versions:
sudo mount -t devtmpfs none /dev
mount | grep ext4
# Verify new size
df -h /
Verifying Disk Space
Check Virtual Disk Size (Windows)
Get-ChildItem -Path "$env:LOCALAPPDATA\Packages" -Recurse -Filter "ext4.vhdx" |
Select-Object FullName, @{Name="Size(GB)";Expression={[math]::Round($_.Length / 1GB, 2)}}
Check Disk Usage Inside WSL
# Overall disk usage
df -h
# Detailed space usage by directory
du -sh /* 2>/dev/null | sort -h
# Find large files
find / -type f -size +100M 2>/dev/null | head -20
Before/After Comparison
# Before compaction
$before = (Get-Item "C:\Users\YourUsername\AppData\Local\Packages\...\ext4.vhdx").Length / 1GB
# After compaction
$after = (Get-Item "C:\Users\YourUsername\AppData\Local\Packages\...\ext4.vhdx").Length / 1GB
Write-Host "Freed: $([math]::Round($before - $after, 2)) GB"
Troubleshooting
Issue: "The process cannot access the file because it is being used"
Solution:
# Ensure WSL is fully shut down
wsl --shutdown
# Wait a few seconds
Start-Sleep -Seconds 5
# Verify no WSL processes
Get-Process | Where-Object {$_.ProcessName -like "*wsl*"}
Issue: "diskpart: The parameter is incorrect"
Solution: Check the file path is correct and use double quotes around the path.
Issue: "Optimize-VHD: Access is denied"
Solution: Run PowerShell as Administrator.
Issue: Compaction doesn't free much space
Solution: Ensure you zeroed out free space inside WSL before compacting. The virtual disk can only shrink blocks that are actually empty.
Issue: Can't find .vhdx file
Solution:
# List all WSL distributions
wsl --list --verbose
# Find the exact package name
Get-AppxPackage | Where-Object {$_.Name -like "*Ubuntu*"}
# Search for vhdx files
Get-ChildItem -Path $env:LOCALAPPDATA -Recurse -Filter "*.vhdx" -ErrorAction SilentlyContinue
Best Practices
1. Regular Maintenance
Compact WSL disks monthly or after:
- Large package removals
- Docker image cleanup
- Temporary file cleanup
- Major updates
2. Monitor Disk Usage
# Create alias for quick disk check
alias diskcheck='df -h / && echo "---" && du -sh ~/* 2>/dev/null | sort -h | tail -10'
3. Clean Up Regularly
# Clean package caches
sudo apt clean
sudo apt autoremove
# Clean Docker (if used)
docker system prune -a
# Clean npm/pip caches
npm cache clean --force
pip cache purge
4. Automate Compaction
Create a scheduled task in Windows to run compaction weekly:
# Create task (run as admin)
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-File C:\Scripts\compact-wsl.ps1"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At 2am
Register-ScheduledTask -TaskName "Compact WSL Disk" -Action $action -Trigger $trigger
5. Backup Before Major Operations
# Export WSL distribution
wsl --export Ubuntu-20.04 C:\Backup\ubuntu-backup.tar
Resources
Need help with WSL optimization or Windows system administration? Contact us for consulting.