TekOnline

Docker Desktop Ate 60GB on Windows: The WSL VHDX Problem and How We Fixed It

Published by TekOnline
Date: 20 May 2026

Docker Desktop on Windows is convenient, especially with the WSL 2 backend. It is also very easy for it to quietly consume a lot of disk space.

Recently, we hit a familiar problem: Docker looked like it had tens of gigabytes of unused data, but even after pruning images and build cache, Windows still showed Docker using around 60GB.

The culprit was not a normal folder full of files. It was Docker Desktop’s WSL virtual disk:

C:\Users\<USER>\AppData\Local\Docker\wsl\disk\docker_data.vhdx

This article explains why that file grows, why Docker cleanup alone is not enough, and the exact process we used to shrink it safely.

The Symptom

Docker was using a large amount of disk space:

docker system df

The initial report showed:

TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          61        18        51.8GB    40.89GB (78%)
Containers      20        2         1.047GB   1.047GB (99%)
Local Volumes   35        11        4.513GB   2.847GB (63%)
Build Cache     653       0         17.14GB   17.14GB

That looked straightforward: prune unused images and build cache.

After cleanup, Docker’s internal usage dropped substantially:

TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          20        18        13.78GB   1.575GB (11%)
Containers      20        2         1.047GB   1.047GB (99%)
Local Volumes   35        11        4.513GB   2.847GB (63%)
Build Cache     0         0         0B        0B

But Windows still showed the Docker VHDX at about 60GB:

C:\Users\<USER>\AppData\Local\Docker\wsl\disk\docker_data.vhdx  60.44GB

That is the confusing part. Docker had freed space internally, but Windows had not reclaimed the physical disk space.

Why This Happens

Docker Desktop on Windows stores Linux container data inside WSL 2. WSL 2 stores its filesystem in a dynamically expanding virtual disk file, a VHDX.

Dynamic VHDX files grow as data is written. They do not necessarily shrink when files are deleted inside Linux. So there are two separate cleanup jobs:

  1. Remove unused Docker objects inside Docker.
  2. Trim and compact the WSL VHDX so Windows can reclaim the freed blocks.

Docker prune commands only handle the first job.

This is why you can delete images, containers, and build cache, then still see a huge docker_data.vhdx file on the Windows side.

Step 1: Check What Docker Can Reclaim

Start with Docker’s own disk usage report:

docker system df

This tells you how much space is used by:

  • Images
  • Containers
  • Volumes
  • Build cache

Volumes need special care. They often contain database files, uploads, local development state, or other data you may not be able to recreate. We did not prune volumes automatically.

Step 2: Prune Unused Images and Build Cache

We removed unused images:

docker image prune -a -f

Then removed build cache:

docker builder prune -a -f

You can also use docker system prune, but be deliberate with flags. In particular, avoid --volumes unless you have confirmed that unused volumes are disposable.

Docker’s own documentation notes that volumes are not removed automatically because doing so can destroy data.

Step 3: Find the Actual VHDX File

To locate Docker’s VHDX files:

Get-ChildItem -Path "$env:LOCALAPPDATA\Docker" -Force -Recurse -Include *.vhdx,*.vhd -ErrorAction SilentlyContinue |
  Select-Object FullName,@{Name='SizeGB';Expression={[math]::Round($_.Length/1GB,2)}} |
  Sort-Object SizeGB -Descending

On our system, the large file was:

C:\Users\<USER>\AppData\Local\Docker\wsl\disk\docker_data.vhdx

It was still around 60GB after Docker pruning.

Step 4: Trim Free Blocks Inside WSL

Before compacting the VHDX from Windows, run fstrim inside Docker’s WSL distribution:

wsl -d docker-desktop -u root -- fstrim -av

This tells the Linux filesystem to mark free blocks as discardable. Without this step, Windows compaction may run but fail to reduce the VHDX file size.

Step 5: Stop Docker and WSL

The VHDX cannot be compacted while Docker or WSL has it open.

Stop Docker Desktop and related backend processes:

Get-Process | Where-Object { $_.ProcessName -match 'Docker|docker|com\.docker' } |
  Stop-Process -Force -ErrorAction SilentlyContinue

Then shut down WSL:

wsl --shutdown
Start-Sleep -Seconds 10

Confirm Docker’s WSL distro is stopped:

wsl -l -v

If the distro is still running, compaction will likely fail with:

The process cannot access the file because it is being used by another process.

Step 6: Compact the VHDX

Run the compaction from an elevated PowerShell prompt.

Create a small DiskPart script:

$dockerVhdx = Join-Path $env:LOCALAPPDATA 'Docker\wsl\disk\docker_data.vhdx'
$script = Join-Path $env:TEMP 'compact-docker-vhdx.diskpart'

Set-Content -LiteralPath $script -Value @"
select vdisk file="$dockerVhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit
"@ -Encoding ASCII

diskpart /s $script
Remove-Item -LiteralPath $script -Force

On our machine, the first compaction attempt failed because Docker still had the file open. After fully stopping Docker Desktop, Docker backend processes, and WSL, DiskPart completed successfully.

The result:

Before: 60.44GB
After:  24.46GB

That recovered roughly 36GB of disk space.

Step 7: Restart Docker Desktop

After compaction:

Start-Process "$env:ProgramFiles\Docker\Docker\Docker Desktop.exe"

Then verify Docker is back:

docker info --format '{{.ServerVersion}}'

Why We Avoided Sparse VHD Mode

Recent WSL versions include a sparse VHD option:

wsl --manage docker-desktop --set-sparse true

On our system, WSL refused to enable it and printed a warning that sparse VHD support was disabled due to potential data corruption. It suggested an --allow-unsafe flag.

We did not use that option. For a production or client machine, anything explicitly labelled unsafe should require careful review, backups, and manual opt-in.

Is This a Known Issue?

Yes. This is a well-known behaviour of Docker Desktop on Windows with WSL 2:

  • WSL 2 VHDX files grow as data is written.
  • Deleting Docker data does not guarantee the host VHDX shrinks.
  • Docker prune cleans Docker’s internal objects, not the Windows virtual disk file.
  • A full reclaim usually requires prune, trim, shutdown, and VHDX compaction.

Microsoft documents WSL disk behaviour and management. Docker documents pruning and the location of Docker Desktop’s disk image. There are also many community reports on Stack Overflow, GitHub, Reddit, and technical blogs describing the same issue.

Is There an Opportunity for a Tool?

Yes. This is low-hanging fruit for a small open-source Windows utility.

The tool should not blindly delete data. The valuable version would be conservative and transparent:

  • Show Docker internal usage from docker system df.
  • Show the physical size of docker_data.vhdx.
  • Explain why those numbers differ.
  • Prune unused images and build cache by default.
  • Leave volumes alone unless explicitly requested.
  • Run fstrim inside Docker’s WSL distro.
  • Stop Docker Desktop and WSL cleanly.
  • Compact the VHDX using diskpartOptimize-VHD, or the Windows VirtDisk API.
  • Restart Docker Desktop.
  • Show before and after sizes.

A safe command-line interface could look like this:

.\docker-vhdx-shrink.ps1

By default, it should print a plan and ask before making changes.

An advanced mode could be:

.\docker-vhdx-shrink.ps1 -PruneImages -PruneBuildCache -Trim -Compact -RestartDocker

The tool should avoid:

  • Pruning Docker volumes by default.
  • Using WSL --allow-unsafe automatically.
  • Killing unrelated WSL distributions without permission.
  • Unregistering Docker WSL distributions.
  • Assuming Hyper-V Optimize-VHD is installed.

This is exactly the type of small utility that would save developers and IT teams time, as long as the defaults are safe.

Practical Takeaway

If Docker Desktop on Windows says it has freed space but your disk is still full, check the VHDX file. You probably need to compact Docker’s WSL virtual disk after pruning.

The short version is:

docker system df
docker image prune -a -f
docker builder prune -a -f
wsl -d docker-desktop -u root -- fstrim -av
wsl --shutdown

Then compact:

diskpart
select vdisk file="C:\Users\<USER>\AppData\Local\Docker\wsl\disk\docker_data.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit

Run the compaction elevated, and make sure Docker Desktop is fully stopped first.

Sources


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *