article
Caching in GitHub Actions
Unlike Jenkins which usually runs builds in the same environment (unless configured differently, it works similar to comparable services like Travis. Every build is executed in a clean (docker) container and will checkout the projects and install required dependencies.
GitHub Actions Introduction
GitHub actions is great, and having a clean environment every time a build is started means that nothing from previous builds can affect the most recent ones.
This comes with a big price though.
Everything has to be built fresh every single time, and that takes time. Fetching dependencies, configuring gradle, fetching git-lfs files, building the project clean.
Ultimately this translate into real world cost, if the free build quota or (if you use git-lfs) the git-lfs bandwidth quota get exhausted.
Luckily there's a solution to this problem: Github Actions Caching.
Caching allows to backup any folder of your build environment to the GitHub Actions cache, and fetch it again the next time a build starts.
For the cache to properly and safely function, you associate a key
which can be generated from your source with the cacheable data.
When starting the next build, it will compare the cache-keys and download and unpack the cache to the old location.
This is great and will help to keep the build times fast, and safe your git-lfs quota.
One caveat of it is the current hard limit of 5GB though. (There's a plan to raise this limit though)
Enable Cache
To setup the cache the official actions/cache@v2
action from GitHub has to be used.
The action will automatically take care of fetching the cache when the build starts, and upload the cache after the build succeeded.
A great example in which the cache makes a lot of sense are for example Android Gradle
projects.
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
!~/.gradle/wrapper/dists/**/gradle*.zip
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
That looks like a lot initially but let's brake it down:
We use the cache action provided by GitHub.
- uses: actions/cache@v2
We want to backup the caches and the wrapper folder.
path: |
~/.gradle/caches
~/.gradle/wrapper
But we want to exclude the zipped wrapper as the .gradle
folder will contain the unpacked executable already.
!~/.gradle/wrapper/dists/**/gradle*.zip
As the unique cache key we will use the operating system (usually caches depend on the OS they were generated on), a unique section -gradle-
to indicate this cache is for the gradle files, and a generated hash based on all *.gradle
files.
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
This hash is important as it will ensure that the best fitting cache will be pulled from the caches, resulting in the cache being much more effective.
The last but also very important bit is the restore-keys
restore-keys: |
${{ runner.os }}-gradle-
If the cache won't find an exact match with the key
, it will fallback to the restore-keys
and pick the second, third, ... most fitting cache.
Assuming we have a hash of 1234
and were using linux
this would result in the following order:
1) linux-gradle-1234
2) linux-gradle-
Looking for a cache with key linux-gradle-1234
we will find an exact match and pick 1
, also the cache won't be uploaded after the build finished, as we already got it.
For a cache with key linux-gradle-4321
, we'd fallback to 2
, as no exact match is found, after a build success it will then upload the cache with this exact key, and keep it for 7 days or until 5gb cache size are reached.


Additional Cache Examples
Android Build Cache
- name: Checkout Android Cache
uses: actions/cache@v2
with:
path: ~/.android/build-cache
key: android-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
android-${{ runner.os }}-
Git-Lfs Cache
- name: Create git-lfs Cache Key
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- name: Cache git-lfs
uses: actions/cache@v2
with:
path: .git/lfs
key: lfs-${{ runner.os }}-${{ hashFiles('.lfs-assets-id') }}
restore-keys: |
lfs-${{ runner.os }}-
Even more cache examples can be found in the cache action repo here.