Guide Beginner 8 min read

Compact & Expand WSL Virtual Disk: Reclaim Disk Space

Learn how to compact and expand WSL virtual disk files (.vhdx) to reclaim disk space and manage storage efficiently. Step-by-step guide with diskpart commands.

OceanSoft Solutions
wslwindowsdiskpartvirtualizationdisk-managementstorage
admin@windows:~

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

  1. Deleted large files inside WSL, but disk space wasn't freed
  2. Removed packages (apt, pip, npm), but .vhdx file still large
  3. Temporary files accumulated over time
  4. 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 --verbose for 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)

  1. Start WSL:

    wsl -d Ubuntu-20.04
    
  2. 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
    
  3. 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)

  1. Open PowerShell as Administrator

  2. Start diskpart:

    diskpart
    
  3. Select your WSL virtual disk:

    select vdisk file="C:\Users\YourUsername\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx"
    
  4. Attach the disk in read-only mode:

    attach vdisk readonly
    
  5. Compact the disk:

    compact vdisk
    
  6. Detach the disk:

    detach vdisk
    
  7. 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.