Caching dependencies to speed up workflows

To make your workflows faster and more efficient, you can create and use caches for dependencies and other commonly reused files.

GitHub Actions is available with GitHub Free, GitHub Pro, GitHub Team, and GitHub Enterprise Cloud. For more information, see "GitHub's products."

In this article

About caching workflow dependencies

Workflow runs often reuse the same outputs or downloaded dependencies from one run to another. For example, package and dependency management tools such as Maven, Gradle, npm, and Yarn keep a local cache of downloaded dependencies.

Jobs on GitHub-hosted runners start in a clean virtual environment and must download dependencies each time, causing increased network utilization, longer runtime, and increased cost. To help speed up the time it takes to recreate these files, GitHub can cache dependencies you frequently use in workflows.

We recommend that you don't store any sensitive information in the cache of public repositories. Forks of a repository have read access to caches on the base branch.

To cache dependencies for a job, you'll need to use GitHub's cache action. The action retrieves a cache identified by a unique key. For more information, see actions/cache.

Comparing artifacts and dependency caching

Artifacts and caching are similar because they provide the ability to store files on GitHub, but each feature offers different use cases and cannot be used interchangeably.

  • Use caching when you want to reuse files that don't change often between jobs or workflow runs.
  • Use artifacts when you want to save files produced by a job to view after a workflow has ended. For more information, see "Persisting workflow data using artifacts."

Using the cache action

The cache action will attempt to restore a cache based on the key you provide. When the action finds a cache it restores the cached files to the path you configure.

If no exact match is found, the action creates a new cache entry on the successful completion of the job. The new cache will use the key you provided and contains the files in the path directory.

You can optionally provide a list of restore-keys that are used when the key doesn't match an existing cache. A list of restore-keys is useful when you are restoring a cache from another branch in a repository because restore-keys can partially match cache keys. For more information about matching restore-keys, see "Matching a cache key."

For more information, see actions/cache.

Input parameters for the cache action

  • key: Required The key created when saving a cache and the key used to search for a cache. Can be any combination of variables, context values, static strings, and functions. Keys have a maximum length of 512 characters, and keys longer than the maximum length will cause the action to fail.
  • path: Required The file path on the runner to cache or restore. This can be an absolute path or relative to the working directory. The path input must be a directory. You cannot cache a single file. The path must be located inside of the GITHUB_WORKSPACE directory. For more information, see "Virtual environments for GitHub Actions."
  • restore-keys: Optional An ordered list of alternative keys to use for finding the cache if no cache hit occurred for key.

Output parameters for the cache action

  • cache-hit: Set to true for a cache hit, and set to false for a cache miss.

Example using the cache action

name: Caching with npm

on: push

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1

    - name: Cache node modules
      uses: actions/cache@v1
      with:
        path: node_modules
        key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.OS }}-build-${{ env.cache-name }}-
          ${{ runner.OS }}-build-
          ${{ runner.OS }}-

    - name: Install Dependencies
      run: npm install

    - name: Build
      run: npm build

    - name: Test
      run: npm test

When key matches an existing cache, it's called a cache hit, and the action restores the cached files to the path directory.

When key doesn't match an existing cache, it's called a cache miss, and a new cache is created if the job completes successfully. When a cache miss occurs, the action searches for alternate keys called restore-keys.

  1. If you provide restore-keys, the cache action sequentially searches for any caches that match the list of restore-keys.

    • When there is an exact match, the action restores the files in the cache to the path directory.
    • If there are no exact matches, the action searches for partial matches of the restore keys. When the action finds a partial match, the most recent cache is restored to the path directory.
  2. The cache action completes and the next workflow step in the job runs.
  3. If the job completes successfully, the action creates a new cache with the contents of the path directory.

To cache files in more than one directory, you will need a step that uses the cache action for each directory. Once you create a cache, you cannot change the contents of an existing cache but you can create a new cache with a new key.

Using contexts to create cache keys

A cache key can include any of the contexts, functions, literals, and operators supported by GitHub Actions. For more information, see "Contexts and expression syntax for GitHub Actions."

Using expressions to create a key allows you to automatically create a new cache when dependencies have changed. For example, you can create a key using an expression that calculates the hash of an npm package-lock.json file.

npm-${{ hashFiles('package-lock.json') }}

GitHub evaluates the expression hash "package-lock.json" to derive the final key.

npm-d5ea0750

Matching a cache key

You can provide a list of restore keys to use when there is a cache miss on key. The cache action searches for restore-keys in sequential order. When a key doesn't match directly, the action searches for keys prefixed with the restore key. If there are multiple partial matches for a restore key, the action returns the most recently created cache.

You can create multiple restore keys ordered from the most specific to least specific.

Example using multiple restore keys

restore-keys: |
  npm-foobar-${{ hashFiles('package-lock.json') }}
  npm-foobar-
  npm-

The runner evaluates the expressions, which resolve to these restore-keys:

restore-keys: |
  npm-foobar-d5ea0750
  npm-foobar-
  npm-

The restore key npm-foobar- matches any key that starts with the string npm-foobar-. For example, both of the keys npm-foobar-fd3052de and npm-foobar-a9b253ff match the restore key. The cache with the most recent creation date would be used. The keys in this example are searched in the following order:

  1. npm-foobar-d5ea0750 matches a specific hash.
  2. npm-foobar- matches cache keys prefixed with npm-foobar-.
  3. npm- matches any keys prefixed with npm-.

Cache scope

When you create a cache, it includes a scope property that indicates the branch of the workflow run. You can restore a cache created in any branch of a repository, including base branches of forked repositories. Scopes provide cache isolation and security by creating a logical boundary between different workflows and branches.

The cache action always searches for cache hits for key and restore-keys in the current scope (the branch containing the workflow run) first. If there are no hits in the current scope, the cache action searches for key and restore-keys in the next scope (the parent or upstream branch).

Example of search priority
key:
  npm-feature-d5ea0750
restore-keys: |
  npm-feature-
  npm-

For example, if a pull request contains a feature branch (the current scope) and targets the default branch (master), the action searches for key and restore-keys in the following order:

  1. Key npm-feature-d5ea0750 in the feature branch scope
  2. Key npm-feature- in the feature branch scope
  3. Key npm- in the feature branch scope
  4. Key npm-feature-d5ea0750 in the master branch scope
  5. Key npm-d5ea0750 in the master branch scope
  6. Key npm in the master branch scope

Usage limits and eviction policy

GitHub will remove any cache entries that have not been accessed in over 7 days. You can store as many cache entries as you'd like for free, as long as you are within these usage limits:

  • Individual files in a cache don't exceed 400 MB. You will receive a 400 - Bad Request if you exceed this limit.
  • The total size of all caches in a repository don't exceed 2 GB. If you exceed this limit, GitHub will save your cache but will begin evicting caches until the total size is less than 2 GB.

Ask a human

Can't find what you're looking for?

Contact us