Answer
Caching Dependencies in GitHub Actions
Without caching, every run downloads all dependencies fresh — slow and wasteful. Caching saves them between runs.
Cache a Maven Project (~/.m2)
YAML
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
# key: exact match (pom.xml unchanged → cache hit)
# restore-keys: partial match fallback (pom.xml changed → use old cache, update after)
- name: Build and test
run: mvn clean verify
Built-in Cache via setup-java (Simpler)
YAML
- name: Set up JDK 17 with Maven cache
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: 'maven' # ← handles caching automatically!
# also supports: 'gradle', 'sbt'
Cache npm / Node.js (Cypress, Playwright)
YAML
- name: Set up Node.js with npm cache
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # ← built-in cache for npm
# cache: 'yarn' or 'pnpm' also supported
- run: npm ci # use ci (not install) for reproducible installs
# Or manual cache:
- name: Cache node_modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
Cache Gradle
YAML
- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
Cache Python (pip)
YAML
- uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip' # built-in pip cache
- run: pip install -r requirements.txt
How Cache Keys Work
CODE
key: ubuntu-latest-maven-abc123 ← exact match → CACHE HIT (fastest)
restore-keys:
ubuntu-latest-maven- ← prefix match → CACHE MISS but partial restore
ubuntu-latest- ← broader fallback
On CACHE HIT: restores files, skips download
On CACHE MISS: downloads normally, saves new cache after job
Cache Limits
- ✓Max cache size per entry: 10 GB
- ✓Cache evicted after 7 days of no use
- ✓Per-repo cache limit: 10 GB (then oldest evicted)
Measuring Cache Impact
YAML
- name: Cache Maven
id: cache-maven
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- name: Check cache status
run: |
if [ "${{ steps.cache-maven.outputs.cache-hit }}" == "true" ]; then
echo "Cache HIT — dependencies restored from cache"
else
echo "Cache MISS — downloading dependencies"
fi
Typical Time Savings
| Project | Without Cache | With Cache |
|---|---|---|
| Maven (200 deps) | 3–5 min | 20–30 sec |
| npm (node_modules) | 2–4 min | 15–25 sec |
| pip (ML packages) | 5–10 min | 30–60 sec |
