WSL Disk Space Cleanup: VHDX, Docker, Model Caches, and What Actually Frees Space
· 28 min read · Views --

WSL Disk Space Cleanup: VHDX, Docker, Model Caches, and What Actually Frees Space

Author: Alex Xiang


One of the easiest WSL problems to panic over is a suddenly full C drive.

You delete tens of gigabytes inside Ubuntu. df -h says space has been freed. Then you go back to Windows and the C drive has barely changed. The ext4.vhdx file is still huge.

This is not an illusion. A WSL2 Linux filesystem is usually stored on Windows as a virtual disk file. Deleting files inside Linux creates free blocks inside that virtual disk. It does not necessarily shrink the VHDX file seen by Windows immediately.

Cleaning WSL disk space, VHDX, Docker, and model caches

This article follows a real firefighting path: the development machine had only 2 GB left on C drive, Docker inside WSL could not run, Node dependency installation failed, and local models could not be downloaded. The goal is not to show off obscure commands. It is to make clear what to inspect, what to delete, and how to confirm that space was actually recovered.

First, Separate Linux Free Space from Windows Free Space

Inside WSL, check:

df -h

Check the root filesystem:

df -h /

Then inspect large directories:

du -h -d 1 ~ | sort -h
sudo du -h -d 1 /var | sort -h

If Docker is installed:

docker system df

If you run local models:

du -sh ~/.cache ~/.ollama ~/models 2>/dev/null

These commands answer one question: what is consuming space inside Linux?

On Windows, inspect the VHDX. For a default Microsoft Store Ubuntu installation, the path is usually under:

%LOCALAPPDATA%\Packages\CanonicalGroupLimited.Ubuntu...\LocalState\ext4.vhdx

Different distributions have different package names. In PowerShell:

wsl -l -v

Then look under %LOCALAPPDATA%\Packages for the matching distribution.

The key point: a smaller du result does not mean ext4.vhdx immediately becomes smaller.

Linux df/du and the Windows ext4.vhdx file size are two different views

Think of it as two ledgers. df and du inspect the ext4 filesystem from inside. Windows File Explorer sees the VHDX file that stores that filesystem. Deleting files in Linux creates reusable space inside the filesystem. To reclaim host disk space, you often need to stop WSL and compact the virtual disk.

Delete the Safest Things First

I start with low-risk caches.

apt cache:

sudo apt clean
sudo apt autoremove --purge -y

Python cache:

find ~ -type d -name '__pycache__' -prune -exec rm -rf {} +
find ~ -type d -name '.pytest_cache' -prune -exec rm -rf {} +

Do not blindly delete every node_modules. First find them:

fd -H '^node_modules$' ~/work -t d \
  | xargs -r du -sh \
  | sort -h

After confirming an old project no longer needs its dependencies:

rm -rf ~/work/old-project/node_modules

Rust, Go, pnpm, Yarn, and npm caches are also common:

du -sh ~/.cargo ~/.cache/go-build ~/go/pkg/mod ~/.npm ~/.pnpm-store ~/.cache/yarn 2>/dev/null

Do not solve everything with rm -rf ~/.cache. Many caches can be rebuilt, but some contain login state, partially downloaded models, or build indexes. Inspect before deleting.

Docker Is a Space Sink, but Easy to Damage

Inspect Docker space separately:

docker system df

List images:

docker image ls

List volumes:

docker volume ls

Remove stopped containers, unused networks, and dangling images:

docker system prune

If you are sure unused images can be removed:

docker system prune -a

Volumes are dangerous. Many development databases store their data in volumes. Do not casually run:

docker volume prune

unless you have confirmed those volumes do not contain data you need.

I usually save a before-and-after report:

docker system df -v > docker-space-before.txt

After cleanup:

docker system df -v > docker-space-after.txt

If something goes wrong, at least you know what was removed.

Give Local Model Caches a Home

AI development machines are easily filled by model caches.

Common locations:

du -sh ~/.cache/huggingface ~/.ollama ~/models 2>/dev/null

Hugging Face:

export HF_HOME="$HOME/models/huggingface"
export TRANSFORMERS_CACHE="$HF_HOME/transformers"
export HF_DATASETS_CACHE="$HOME/datasets/huggingface"

Ollama:

du -sh ~/.ollama 2>/dev/null
ollama list

If a model is no longer needed, prefer the tool’s own command:

ollama rm qwen2.5:7b

Do not randomly delete individual blobs from a model directory. Many model managers use content addressing, reference counts, or manifests. Manual deletion can leave a half-broken state.

For local AI projects, I like this directory convention:

~/models/       # model weights
~/datasets/     # datasets
~/runs/         # experiment outputs
~/archive/      # cleanup-friendly archive

Then check weekly:

du -h -d 1 ~/models ~/datasets ~/runs 2>/dev/null | sort -h

Treat model caches, Docker images, node_modules, and apt caches separately

Disk cleanup should not only ask “which directory is largest?” Model caches may need recent versions. Docker images can often be rebuilt per project. node_modules is large but usually recoverable. apt cache is low risk. Once categories are clear, cleanup becomes much safer.

Why the Windows C Drive Does Not Shrink After Deletion

Because you have only made free blocks inside the ext4 filesystem. The VHDX file may still keep its previous size.

Microsoft’s WSL disk-space documentation describes virtual disk management. Newer WSL versions support:

wsl --manage <Distro> --resize <Size>

But “resize capacity” and “return host disk space” are different operations. Resizing changes the virtual disk limit. Reclaiming host disk space makes the VHDX file smaller on Windows.

Before reclaiming, shut down WSL:

wsl --shutdown

Then choose a method based on Windows and WSL versions.

Some environments can rely on sparse VHD support. Others need Optimize-VHD, which belongs to the Hyper-V module and is not available by default on every Windows edition.

If available:

Optimize-VHD -Path "C:\path\to\ext4.vhdx" -Mode Full

Before running it, confirm that the path is the correct distribution’s VHDX and WSL has been shut down.

If the command is not available, the conservative but riskier route is export and re-import:

wsl --export Ubuntu D:\backup\ubuntu.tar
wsl --unregister Ubuntu
wsl --import Ubuntu D:\WSL\Ubuntu D:\backup\ubuntu.tar --version 2

This path is riskier because --unregister deletes the original distribution. Before doing it, confirm the export is valid, you have a backup, and you know how to restore. Do not try this for the first time at midnight with zero bytes left on C drive.

A Small Inspection Script

I keep a ~/bin/wsl-space-report:

#!/usr/bin/env bash
set -euo pipefail

echo "== filesystem =="
df -h /
echo

echo "== home top =="
du -h -d 1 "$HOME" 2>/dev/null | sort -h | tail -20
echo

echo "== work node_modules =="
fd -H '^node_modules$' "$HOME/work" -t d 2>/dev/null \
  | xargs -r du -sh \
  | sort -h \
  | tail -20
echo

echo "== model caches =="
du -sh "$HOME/.cache/huggingface" "$HOME/.ollama" "$HOME/models" "$HOME/datasets" 2>/dev/null || true
echo

if command -v docker >/dev/null 2>&1; then
  echo "== docker =="
  docker system df || true
fi

Make it executable:

chmod +x ~/bin/wsl-space-report

When C drive turns red, run this first. Do not delete by instinct.

My Cleanup Order

My usual order:

  1. Run wsl-space-report to find the largest contributors.
  2. Clean apt, Python, and test caches.
  3. Remove node_modules and .venv from abandoned projects.
  4. Inspect images and volumes with docker system df -v.
  5. Remove unused models.
  6. Archive ~/runs and large datasets.
  7. Run wsl --shutdown.
  8. Compact or migrate the VHDX only when needed.

Do not start by compacting the VHDX. If internal junk remains, compacting is meaningless.

When to Rebuild a Clean Distribution

If a WSL distribution has been used for two or three years and now contains countless projects, old language runtimes, abandoned databases, scattered models, and half-broken Docker volumes, rebuilding may be better than cleaning.

Export the old distribution:

wsl --export Ubuntu D:\backup\ubuntu-old.tar
wsl --install -d Ubuntu

Then migrate only:

  • still-maintained projects under ~/work;
  • explicitly needed configs such as .ssh and .gnupg;
  • dotfiles;
  • required models and data;
  • utility scripts.

Rebuilding is not giving up. It is clearing years of temporary state.

Summary

WSL disk problems are easy to misread because there are two spaces:

Linux free space.
The VHDX file size seen by Windows.

Cleanup should first identify the real consumers inside Linux. Then decide whether to remove caches, dependencies, images, models, or archived data. Once the inside is clean, consider reclaiming VHDX space.

Do not treat “C drive is full” as a single isolated issue. It usually reflects development habits: where projects live, how Docker is used, how model caches are managed, and whether old experiment output is archived.

References