How to use caching in CI/CD with GitHub Actions

Kenny DuMez
Kenny DuMez
Graphite software engineer

Continuous Integration and Continuous Deployment (CI/CD) are practices designed to automate the process of software delivery. They integrate code changes more frequently and ensure that software can be reliably released at any time. GitHub Actions is a powerful tool for automating software workflows, including CI/CD pipelines. In this guide, we'll explore how to use caching to optimize your GitHub Actions workflows, which can significantly reduce build times and improve efficiency.

Caching in GitHub Actions allows you to reuse files or data between workflow runs, saving time that would otherwise be spent setting up your environment or dependencies from scratch in each run. When a workflow is rerun, instead of downloading or generating the same data, the cache is pulled from the stored location, making subsequent runs faster.

  1. Cache action: GitHub provides a dedicated action (actions/cache) designed to facilitate caching of dependencies and other frequently reused files.
  2. Cache key: A key that uniquely identifies the cache. It can be a static string or constructed dynamically using expressions. The key is used to fetch and store the cache.
  3. Paths to cache: Specifies the file paths or directories you want to cache. These paths can vary based on what dependencies or tools you are using in your project.

To implement caching, you must modify your GitHub Actions workflow file (usually .github/workflows/main.yml). Here's how you can cache dependencies for a Node.js project:

Terminal
name: Node.js CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cache node modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install Dependencies
run: npm install
- name: Build
run: npm run build
- name: Test
run: npm test
  • actions/checkout@v2: Checks out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
  • actions/cache@v2: This step sets up caching for the ~/.npm directory where npm stores its cache. The key is generated based on the OS of the runner and the hash of package-lock.json, ensuring that a change in dependencies updates the cache.
  • Restore keys: Provide fallback keys if the exact key match is not found. This allows the use of partial cache matches, which can prevent having to rebuild or reinstall all dependencies from scratch.
  • Be specific with cache paths: Target the directories that store your dependencies, such as node_modules in Node.js projects or vendor/bundle in Ruby projects.
  • Use precise keys: Including hashes of lock files (package-lock.json, yarn.lock, or Gemfile.lock) in your cache key ensures that the cache is only used when the dependencies are the same.
  • Clean up cache: Regularly update your cache keys and clear old or unused caches in your GitHub Actions settings to prevent cache bloating.

To monitor the effectiveness of your caching strategy, you can review the time taken for each job in the Actions tab of your GitHub repository. If certain steps are consistently slow, it may be worth adjusting your cache configuration.

Troubleshooting cache issues typically involves checking the cache key matches and ensuring that the paths cached are correctly configured. Logs in GitHub Actions will provide details if there are any errors during the restore or save cache steps.

By understanding and implementing caching effectively in GitHub Actions, you can significantly reduce build times, save costs by reducing resource consumption, and speed up your development cycle.

Graphite
Git stacked on GitHub

Stacked pull requests are easier to read, easier to write, and easier to manage.
Teams that stack ship better software, faster.

Or install our CLI.
Product Screenshot 1
Product Screenshot 2