HTTP Caching for GitHub Actions

Fedor Korotkov
CirrusLabs
Published in
2 min readSep 9, 2020

Effective caching is by far the best option for speeding up your CI builds. You can optimize some computations and throw more CPUs on the problem but nothing is more efficient than just not doing the work at all by reusing cached results from some previous CI builds.

All popular CI systems including GitHub Actions allows you to do some basic caching by persisting folders and reusing them in the next runs. Here is a configuration example from the official GitHub Docs for caching Gradle’s caches:

- name: Cache Gradle packages
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle

Similar technique can be applied for Node.js Modules, Go Packages, etc.

But Gradle as well as some other modern build systems like Bazel, Buck, Pants and Please can have a more granular caching. These build systems can cache intermediate results of compilers/preprocessors/linters on per-module level of your repository. All these build systems share the same API for remote caching. You simply need an HTTP server that handles GET and POST/PUT requests for downloading and uploading cache blobs.

With a usual folder you are getting “all or nothing caching” and with HTTP Caching you are getting incremental caching caching.

Unfortunately, the default GitHub Action for Caching supports only folder caching even though under the hood it does downloads/uploads from/to Azure via an HTTP API. Luckily the protocol is somewhat open sourced but not documented. It was still manageable to “reverse engineer and write a proxy server in Go that exposes an API for build systems and internally uses the Azure API for actual downloads/uploads.

Introducing, cirruslabs/http-cache-action action that starts a proxing HTTP Caching server for you builds! Please refer to documentation for more details about installation.

--

--