Skill Store 33

Github Actions Cache Optimization

GitHub Actions cache analysis and optimization.

by laurigates · MIT

The skill

GitHub Actions cache analysis and optimization. Use when investigating cache bloat, finding stale caches, optimizing keys, or comparing cache usage across repos.

GitHub Actions Cache Optimization

Analyze cache usage, identify bloat, and optimize cache strategies for GitHub Actions.

When to Use This Skill

Use this skill when... Use X instead when...
Analyzing cache size and count Investigating workflow run failures → gh-workflow-monitoring
Identifying stale or bloated caches Analyzing billing/minutes → github-actions-finops
Optimizing cache key strategies Setting up new cache actions → github-actions-workflows
Cleaning up old caches General workflow efficiency → github-actions-finops

Cache Limits

Limit Value
Max cache size 10 GB per repository
Max single entry 10 GB
Retention 7 days without access
Eviction LRU when limit exceeded

Org-Level Cache Usage

# Total cache usage across org
gh api /orgs/$GITHUB_ORG/actions/cache/usage \
  --jq '{total_active_caches_count, total_active_caches_size_in_bytes}'

# Formatted output
gh api /orgs/$GITHUB_ORG/actions/cache/usage \
  --jq '"\(.total_active_caches_count) caches, \(.total_active_caches_size_in_bytes / 1024 / 1024 | floor)MB total"'

Per-Repo Cache Usage

Cache Summary

# Basic cache stats for repo
gh api "/repos/$OWNER/$REPO/actions/cache/usage" \
  --jq '{active_caches_count, active_caches_size_in_bytes}'

# Formatted
gh api "/repos/$OWNER/$REPO/actions/cache/usage" \
  --jq '"\(.active_caches_count) caches, \(.active_caches_size_in_bytes / 1024 / 1024 | floor)MB"'

Cache List and Breakdown

# List all caches
gh api "/repos/$OWNER/$REPO/actions/caches?per_page=100" \
  --jq '.actions_caches[] | "\(.key): \(.size_in_bytes / 1024 / 1024 | floor)MB, last used: \(.last_accessed_at)"'

# Group by key prefix (first 3 segments)
gh api "/repos/$OWNER/$REPO/actions/caches?per_page=100" \
  --jq '.actions_caches | group_by(.key | split("-") | .[0:3] | join("-")) |
        map({prefix: .[0].key | split("-") | .[0:3] | join("-"),
             count: length,
             size_mb: (map(.size_in_bytes) | add / 1024 / 1024 | floor)}) |
        sort_by(-.size_mb)'

# Caches by branch
gh api "/repos/$OWNER/$REPO/actions/caches?per_page=100" \
  --jq '.actions_caches | group_by(.ref) |
        map({branch: .[0].ref, count: length,
             size_mb: (map(.size_in_bytes) | add / 1024 / 1024 | floor)}) |
        sort_by(-.size_mb)'

Stale Cache Detection

# Caches not accessed in 7+ days (candidates for cleanup)
gh api "/repos/$OWNER/$REPO/actions/caches?per_page=100" \
  --jq --arg cutoff "$(date -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ)" \
  '.actions_caches[] | select(.last_accessed_at < $cutoff) |
   "\(.key): \(.size_in_bytes / 1024 / 1024 | floor)MB, last: \(.last_accessed_at)"'

# macOS date variant
gh api "/repos/$OWNER/$REPO/actions/caches?per_page=100" \
  --jq --arg cutoff "$(date -v-7d +%Y-%m-%dT%H:%M:%SZ)" \
  '.actions_caches[] | select(.last_accessed_at < $cutoff) | ...'

Cache Cleanup

Delete Specific Cache

# Delete cache by ID
gh api -X DELETE "/repos/$OWNER/$REPO/actions/caches/$CACHE_ID"

# Delete cache by key (exact match)
gh api -X DELETE "/repos/$OWNER/$REPO/actions/caches?key=$CACHE_KEY"

Bulk Cleanup

# Delete all caches for a specific branch
gh api "/repos/$OWNER/$REPO/actions/caches?per_page=100&ref=refs/heads/$BRANCH" \
  --jq '.actions_caches[].id' | while read id; do
    gh api -X DELETE "/repos/$OWNER/$REPO/actions/caches/$id"
  done

# Delete caches matching key prefix
gh api "/repos/$OWNER/$REPO/actions/caches?per_page=100" \
  --jq '.actions_caches[] | select(.key | startswith("PREFIX-")) | .id' | while read id; do
    gh api -X DELETE "/repos/$OWNER/$REPO/actions/caches/$id"
  done

Cache Bloat Indicators

Indicator Threshold Issue
Total size >5 GB Approaching 10GB limit
Cache count >50 Too many keys/branches
Stale caches >20% older than 7d Inefficient key strategy
Single cache >2 GB Consider splitting
Branch caches Many closed PR branches Missing cleanup workflow

Cache Key Strategies

Good Key Patterns

# OS + lockfile hash (recommended)
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

# With restore keys for partial matches
restore-keys: |
  ${{ runner.os }}-node-

# Include tool version
key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}

Problematic Patterns

Pattern Issue Fix
${{ github.sha }} in key Never reused Use lockfile hash
${{ github.run_id }} Never reused Remove from key
No restore-keys Cache misses Add fallback keys
Branch in key PR cache bloat Use base branch fallback

Cache Cleanup Workflow

Add to repository for automatic cleanup:

name: Cache Cleanup
on:
  pull_request:
    types: [closed]
  schedule:
    - cron: '0 0 * * 0'  # Weekly

jobs:
  cleanup:
    runs-on: ubuntu-latest
    steps:
      - name: Cleanup PR caches
        if: github.event_name == 'pull_request'
        run: |
          gh api "/repos/${{ github.repository }}/actions/caches?ref=refs/heads/${{ github.head_ref }}" \
            --jq '.actions_caches[].id' | while read id; do
              gh api -X DELETE "/repos/${{ github.repository }}/actions/caches/$id" || true
            done
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Cleanup stale caches
        if: github.event_name == 'schedule'
        run: |
          # Delete caches not accessed in 14 days
          cutoff=$(date -d '14 days ago' +%Y-%m-%dT%H:%M:%SZ)
          gh api "/repos/${{ github.repository }}/actions/caches?per_page=100" \
            --jq --arg cutoff "$cutoff" \
            '.actions_caches[] | select(.last_accessed_at < $cutoff) | .id' | while read id; do
              gh api -X DELETE "/repos/${{ github.repository }}/actions/caches/$id" || true
            done
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Multi-Repo Cache Comparison

# Compare cache usage across repos
for repo in repo1 repo2 repo3; do
  echo "=== $repo ==="
  gh api "/repos/$GITHUB_ORG/$repo/actions/cache/usage" \
    --jq '"\(.active_caches_count) caches, \(.active_caches_size_in_bytes / 1024 / 1024 | floor)MB"'
done

# Full org scan
gh repo list $GITHUB_ORG --json nameWithOwner --limit 100 --jq '.[].nameWithOwner' | while read repo; do
  size=$(gh api "/repos/$repo/actions/cache/usage" --jq '.active_caches_size_in_bytes // 0' 2>/dev/null)
  if [ "$size" -gt 0 ]; then
    echo "$repo: $((size / 1024 / 1024))MB"
  fi
done | sort -t: -k2 -n -r | head -20

Agentic Optimizations

Context Command
Org total gh api /orgs/$ORG/actions/cache/usage --jq '.total_active_caches_size_in_bytes / 1024 / 1024 | floor'
Repo summary gh api "/repos/$O/$R/actions/cache/usage" --jq '"\(.active_caches_count) caches, \(.active_caches_size_in_bytes / 1048576 | floor)MB"'
List caches gh api "/repos/$O/$R/actions/caches?per_page=30" --jq '.actions_caches[] | "\(.key): \(.size_in_bytes / 1048576 | floor)MB"'
By prefix gh api "..." --jq '.actions_caches | group_by(.key | split("-") | .[0]) | map({prefix: .[0].key | split("-") | .[0], count: length})'
Delete cache gh api -X DELETE "/repos/$O/$R/actions/caches/$ID"

Quick Reference

API Endpoint Method Purpose
/orgs/{org}/actions/cache/usage GET Org-wide cache stats
/repos/{owner}/{repo}/actions/cache/usage GET Repo cache stats
/repos/{owner}/{repo}/actions/caches GET List all caches
/repos/{owner}/{repo}/actions/caches/{id} DELETE Delete specific cache
/repos/{owner}/{repo}/actions/caches?key={key} DELETE Delete by key

See Also

  • github-actions-finops - Billing and workflow efficiency analysis
  • gh-workflow-monitoring - Watching workflow runs

Use this skill

Connect your agent to the Skill Store MCP server and ask for it by ref: laurigates/github-actions-cache-optimization-95694788039.

Download SKILL.md · Markdown version

Details

Publisher
laurigates
Category
Software Development › DevOps & cloud
License
MIT
Updated
2026-10-19

References

More from laurigates