GitHub Actions 'No Space Left on Device': How to Fix Runner Disk Issues
GitHub Actions failing with 'no space left on device'? Here's how to free disk space on runners, optimize Docker builds, and handle large monorepos.
Your CI/CD pipeline was working fine for months. Then one day: no space left on device. Docker builds fail. npm install crashes. Artifact uploads time out. The GitHub-hosted runner ran out of disk space.
This is becoming the most common GitHub Actions failure for teams with Docker-heavy pipelines and growing codebases. Here's how to fix it permanently.
Why Runners Run Out of Space
GitHub-hosted runners (ubuntu-latest) come with approximately 14GB of free disk space. That sounds like a lot until you realize the runner also includes:
- 8GB+ of pre-installed tools (Android SDK, .NET, Haskell, etc.)
- Docker images cached from previous layers
- Your repository checkout
- Build artifacts and node_modules
A typical pipeline that builds a Docker image, runs tests, and pushes to a registry can easily consume 10-15GB.
Fix 1 — Free Space by Removing Pre-installed Software
The nuclear option — remove software you don't need. This is the most effective fix:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf /usr/local/share/boost
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/hostedtoolcache
sudo docker system prune -af
df -hThis typically frees 10-15GB of disk space. The df -h at the end shows how much space you recovered:
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 84G 24G 57G 30% /
Use a Community Action (Cleaner Approach)
- name: Free disk space
uses: jlumbroso/free-disk-space@main
with:
tool-cache: true
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: trueThis action handles cleanup comprehensively and is maintained by the community.
Fix 2 — Use /mnt for Docker Builds
The runner's /mnt directory has additional space. Move Docker's storage there:
- name: Move Docker data to /mnt
run: |
sudo systemctl stop docker
sudo mv /var/lib/docker /mnt/docker
sudo ln -s /mnt/docker /var/lib/docker
sudo systemctl start docker
docker info | grep "Docker Root Dir"This gives Docker access to the full /mnt partition, which typically has 50GB+ of free space.
Fix 3 — Optimize Docker Builds
Use Multi-Stage Builds
Multi-stage builds keep only the final artifacts, dramatically reducing intermediate layer sizes:
# Stage 1: Build (large, temporary)
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production (small, final)
FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]The builder stage might use 2GB. The final image is 200MB.
Use .dockerignore
Prevent unnecessary files from being sent to the Docker daemon:
node_modules
.git
*.md
.env*
test/
coverage/
.next/
dist/
Build with --no-cache When Needed
- name: Build Docker image
run: docker build --no-cache -t my-app:${{ github.sha }} .Cached layers consume disk space. When space is tight, skip the cache.
Fix 4 — Clean Up Between Steps
If your workflow has multiple Docker-heavy steps, clean up between them:
- name: Build and test
run: |
docker compose up -d
npm run test:integration
docker compose down --volumes --rmi all
- name: Build production image
run: |
docker build -t my-app:latest .
docker push my-app:latest
docker rmi my-app:latestKey commands:
docker compose down --volumes --rmi all— removes containers, volumes, AND imagesdocker system prune -af— removes everything unuseddocker rmi $(docker images -q)— removes all images
Fix 5 — Handle Large Repositories
For monorepos, a full git clone can consume gigabytes:
- uses: actions/checkout@v4
with:
fetch-depth: 1 # Shallow clone — only latest commit
sparse-checkout: |
src/
package.json
Dockerfilefetch-depth: 1— only clones the latest commit, not full historysparse-checkout— only clones specific directories (huge savings for monorepos)
Fix 6 — Manage Artifacts Efficiently
Compress Before Uploading
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
compression-level: 9
retention-days: 3 # Don't keep foreverDownload Only What You Need
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: build-output
path: dist/Clean Up Old Artifacts
Add a cleanup job at the end of your workflow:
cleanup:
runs-on: ubuntu-latest
needs: [build, test, deploy]
if: always()
steps:
- uses: geekyeggo/delete-artifact@v4
with:
name: build-outputFix 7 — Cache Smartly
npm/yarn Cache (Don't Cache node_modules)
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm' # Caches ~/.npm, not node_modulesDocker Layer Cache with BuildKit
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build with cache
uses: docker/build-push-action@v5
with:
push: true
tags: my-app:latest
cache-from: type=gha
cache-to: type=gha,mode=maxGitHub Actions cache (type=gha) stores Docker layers in the Actions cache instead of on disk.
Fix 8 — Use Larger Runners
If you consistently need more space, use larger runners:
jobs:
build:
runs-on: ubuntu-latest-16-cores # 16 CPU, 64GB RAM, more diskOr self-hosted runners with custom disk sizes:
jobs:
build:
runs-on: self-hostedSelf-hosted runners give you full control over disk size, Docker cache, and pre-installed tools.
Monitoring Disk Usage
Add disk monitoring to catch issues before they crash your pipeline:
- name: Check disk space
run: |
echo "=== Disk Usage ==="
df -h /
echo ""
echo "=== Docker Usage ==="
docker system df
echo ""
echo "=== Largest Directories ==="
du -sh /home/runner/work/* 2>/dev/null | sort -rh | head -10Add this after each major step to identify which step consumes the most space.
Complete Optimized Workflow
Here's a complete workflow with all optimizations applied:
name: Build and Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Free disk space
uses: jlumbroso/free-disk-space@main
with:
tool-cache: true
android: true
dotnet: true
haskell: true
large-packages: true
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Final disk check
if: always()
run: df -h /Quick Reference
| Problem | Solution | Space Saved |
|---|---|---|
| Pre-installed tools | Remove dotnet, android, haskell | 10-15GB |
| Docker data dir full | Move to /mnt | 30-50GB available |
| Large Docker images | Multi-stage builds | 50-80% |
| Full git history | fetch-depth: 1 | 1-5GB |
| Docker layer cache | Use GHA cache, not disk | 2-8GB |
| Old artifacts | Set retention-days, delete after | 1-5GB |
Wrapping Up
"No space left on device" is a solvable problem. Start with removing pre-installed software (Fix 1) — that alone solves 80% of cases. Then optimize your Docker builds and add cleanup steps.
The key principle: GitHub runners are ephemeral. Don't try to cache everything — cache strategically and clean aggressively.
Want to master GitHub Actions and CI/CD pipelines? KodeKloud's CI/CD courses cover pipeline design, Docker optimization, and production-grade workflows with hands-on labs.
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
GitHub Actions vs GitLab CI vs CircleCI — Which One Should You Use in 2026?
Comparing the three most popular CI/CD platforms head-to-head: features, pricing, speed, and when to pick each one in 2026.
Build a Complete CI/CD Pipeline with GitHub Actions + ArgoCD + EKS (2026)
A full project walkthrough — from a simple app to a production-grade GitOps pipeline with automated builds, image scanning, and deployments to AWS EKS using ArgoCD.
Build a DevSecOps Pipeline with Trivy, SonarQube, and OPA from Scratch (2026)
Step-by-step project walkthrough: add security scanning, code quality gates, and policy enforcement to a GitHub Actions pipeline. Real configs, production-ready.