GitHub - Runner Maintenance: Reclaim Filesystem - reclaim disk space on GitHub runners.
GitHub-hosted runners come with a lot of pre-installed software you probably don't need. This action removes the bloat and optionally merges multiple disks into a single large volume.
- Fast deletion using rmz (parallel, Rust-based rm)
- Configurable cleanup - choose what to remove
- Disk merging - combine root and
/mntinto a single LVM volume (~100GB) - Custom mount path - mount merged volume at
$GITHUB_WORKSPACEor/var/lib/docker/for Docker builds - Btrfs support - optional zstd compression for even more space
- uses: fenio/gh-rmrf@v1This removes ~20GB of bloat (Android SDK, .NET, Haskell, Boost, Swift, CodeQL).
Important: When using
merge-disks: true, the action mounts a fresh filesystem at$GITHUB_WORKSPACE. This means it must run beforeactions/checkout, so the code gets checked out onto the merged volume.
jobs:
build:
runs-on: ubuntu-latest
steps:
# gh-rmrf must run FIRST when using merge-disks
- uses: fenio/gh-rmrf@v1
with:
merge-disks: 'true'
# Now checkout into the merged workspace
- uses: actions/checkout@v6
# Your build steps...Creates a ~100GB unified workspace by combining freed space with the /mnt disk.
jobs:
build:
runs-on: ubuntu-latest
steps:
# gh-rmrf must run FIRST when using merge-disks
- uses: fenio/gh-rmrf@v1
with:
merge-disks: 'true'
use-btrfs: 'true'
# Now checkout into the merged workspace
- uses: actions/checkout@v6Uses Btrfs with zstd compression for the merged volume.
When building large Docker images that exceed the default disk space, you can mount the merged volume directly at Docker's data directory. This requires backing up and restoring Docker data around the merge operation.
jobs:
build:
runs-on: ubuntu-latest
steps:
# 1. Backup Docker data BEFORE merge
- name: Backup Docker data
run: |
sudo mkdir -p /tmp/docker-backup
sudo rsync -aPq /var/lib/docker/ /tmp/docker-backup/
# 2. Run gh-rmrf with custom mount path
- uses: fenio/gh-rmrf@v1
with:
merge-disks: 'true'
mount-path: '/var/lib/docker/'
# 3. Restore Docker data AFTER merge
- name: Restore Docker data
run: |
sudo rsync -aPq /tmp/docker-backup/ /var/lib/docker/
sudo rm -rf /tmp/docker-backup
# 4. Now checkout and build
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: your-image:latestThis gives Docker access to the full ~100GB merged volume for building large images.
- uses: fenio/gh-rmrf@v1
with:
remove-android: 'true' # ~12GB
remove-dotnet: 'true' # ~2GB
remove-haskell: 'true' # ~2GB
remove-boost: 'true' # ~1GB
remove-swift: 'true' # ~1.5GB
remove-codeql: 'true' # ~1GB
remove-hostedtoolcache: 'false' # ~8GB - Go, Node.js, Python, Ruby, etc.
remove-docker-images: 'false' # ~4GB
nuke: 'false' # Experimental: nuke browsers, databases, cloud CLIs
merge-disks: 'false'
use-btrfs: 'false'| Input | Description | Default |
|---|---|---|
remove-android |
Remove Android SDK (~12GB) | true |
remove-dotnet |
Remove .NET SDK (~2GB) | true |
remove-haskell |
Remove GHC/Haskell (~2GB) | true |
remove-boost |
Remove Boost (~1GB) | true |
remove-swift |
Remove Swift (~1.5GB) | true |
remove-codeql |
Remove CodeQL (~1GB) | true |
remove-hostedtoolcache |
Remove cached tool versions - Go, Node.js, Python, Ruby, etc. (~8GB) | false |
remove-docker-images |
Remove Docker images (~4GB) | false |
nuke |
Experimental: Remove browsers, databases, cloud CLIs, build tools | false |
merge-disks |
Merge root and /mnt into single LVM volume | false |
mount-path |
Path where merged volume will be mounted (defaults to $GITHUB_WORKSPACE) |
'' |
use-btrfs |
Use Btrfs with zstd compression (requires merge-disks) | false |
- Reports initial disk usage
- Downloads
rmzfor fast parallel deletion - Removes selected bloat directories
- Reports final disk usage
Note: The disk merging feature is somewhat hackish - it relies on undocumented details of GitHub runner disk layout that could change without notice. It works today, but use at your own risk.
- Removes bloat (as above)
- Disables swap and unmounts
/mnt - Creates a loopback file from freed space on root (~80% of available)
- Creates LVM volume group combining the former
/mntdisk and loopback - Formats as ext4 or Btrfs (with zstd compression)
- Mounts at
$GITHUB_WORKSPACE(default) or custommount-path
| Mode | Before | After | Free space |
|---|---|---|---|
| Cleanup only | 55GB used, 18GB free | 35GB used, 38GB free | ~38GB on root |
| Cleanup + nuke | 55GB used, 18GB free | 14GB used, 58GB free | ~58GB on root |
| Merge (ext4) | - | - | ~100GB unified |
| Merge (Btrfs+zstd) | - | - | ~100GB+ unified |
| Maximum (all + nuke + merge) | 55GB used, 18GB free | 25GB used, 47GB free | ~113GB unified |
| Path | Size | Removed by |
|---|---|---|
/usr/local/lib/android |
~12GB | remove-android |
/opt/hostedtoolcache |
~8GB | remove-hostedtoolcache |
/usr/share/dotnet |
~2GB | remove-dotnet |
/opt/ghc |
~2GB | remove-haskell |
/usr/local/.ghcup |
~1GB | remove-haskell |
/usr/local/share/boost |
~1GB | remove-boost |
/usr/share/swift |
~1.5GB | remove-swift |
/opt/hostedtoolcache/CodeQL |
~1GB | remove-codeql |
| Docker images | ~4GB | remove-docker-images |
The nuke option aggressively removes additional bloat, freeing ~40GB total when combined with default cleanup:
| Category | Paths | Size |
|---|---|---|
| Browsers | Chrome, Firefox, Edge, Chromium | ~1.5GB |
| Cloud CLIs | Azure, GCloud, AWS CLI, AWS SAM | ~2GB |
| Databases | PostgreSQL, MySQL | ~0.5GB |
| Languages | Julia, Miniconda, Rust toolchains | ~2.5GB |
| Build tools | Gradle, Kotlin, Maven, LLVM versions | ~2GB |
| Other | PowerShell, Linuxbrew, Java VMs, Minikube, Runner cache | ~2.5GB |
Warning: The nuke option removes tools you might need. Java VMs, LLVM, and build tools are removed. Only use this if you're sure your workflow doesn't depend on these.
MIT