Introduction

GitHub Actions caching speeds up builds, but large caches eventually fail to save. The usual cause is trying to cache heavyweight directories such as node_modules, generated build trees, or language toolchains wholesale. When cache archives grow too large, the save step warns or fails and subsequent workflows lose the expected cache benefit.

Symptoms

  • The post-job cache save step warns that the cache exceeded the allowed size
  • Builds become slower because cache restore works inconsistently or not at all
  • Repository cache storage keeps growing even when dependency changes are small
  • Teams cache whole dependency directories instead of package manager download caches

Common Causes

  • node_modules, .venv, or other bulky runtime directories are cached directly
  • One cache key is reused for too many unrelated files
  • Old caches accumulate without cleanup or natural churn
  • Build outputs and dependency caches are mixed into one archive

Step-by-Step Fix

  1. 1.Cache package manager artifacts, not full install directories
  2. 2.Package manager caches are usually much smaller and more stable than installed dependency trees.
yaml
- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: npm
  1. 1.Split caches by purpose
  2. 2.Keep dependency caches separate from framework build caches so one fast-changing directory does not bloat everything else.
yaml
- uses: actions/cache@v4
  with:
    path: .next/cache
    key: nextjs-${{ hashFiles('package-lock.json') }}
  1. 1.Remove stale or oversized caches
  2. 2.If the repository cache store is already bloated, cleanup may be required before the new strategy becomes effective.
  3. 3.Measure what is actually being cached
  4. 4.Check directory sizes before adding them to cache configuration. Many teams never validate the archive size until the save step fails.

Prevention

  • Prefer built-in language cache features from setup actions where available
  • Avoid caching full install trees unless you have a very specific reason
  • Separate dependency caches from generated build artifacts
  • Review cache growth periodically instead of waiting for save failures