- C# - NuGet
- Clojure - Lein Deps
- D - DUB
- Deno
- Elixir - Mix
- Erlang - Rebar3
- Go - Modules
- Haskell - Cabal
- Haskell - Stack
- Java - Gradle
- Java - Maven
- Node - npm
- Node - Lerna
- Node - Yarn
- Node - Yarn 2
- OCaml/Reason - esy
- PHP - Composer
- Python - pip
- Python - pipenv
- R - renv
- Ruby - Bundler
- Rust - Cargo
- Scala - SBT
- Swift, Objective-C - Carthage
- Swift, Objective-C - CocoaPods
- Swift - Swift Package Manager
- Swift - Mint
- * - Bazel
Using NuGet lock files:
- uses: actions/cache@v3
with:
paths: ~/.nuget/packages
primary-key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-prefixes-first-match: |
${{ runner.os }}-nuget-
Depending on the environment, huge packages might be pre-installed in the global cache folder.
With actions/cache@v3
you can now exclude unwanted packages with exclude pattern
- uses: actions/cache@v3
with:
paths: |
~/.nuget/packages
!~/.nuget/packages/unwanted
primary-key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-prefixes-first-match: |
${{ runner.os }}-nuget-
Or you could move the cache folder like below.
Note This workflow does not work for projects that require files to be placed in user profile package folder
env:
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
steps:
- uses: actions/cache@v3
with:
paths: ${{ github.workspace }}/.nuget/packages
primary-key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-prefixes-first-match: |
${{ runner.os }}-nuget-
- name: Cache lein project dependencies
uses: actions/cache@v3
with:
paths: ~/.m2/repository
primary-key: ${{ runner.os }}-clojure-${{ hashFiles('**/project.clj') }}
restore-prefixes-first-match: |
${{ runner.os }}-clojure
- uses: actions/cache@v3
with:
paths: ~/.dub
primary-key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.selections.json') }}
restore-prefixes-first-match: |
${{ runner.os }}-dub-
- uses: actions/cache@v3
with:
paths: ~\AppData\Local\dub
primary-key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.selections.json') }}
restore-prefixes-first-match: |
${{ runner.os }}-dub-
- uses: actions/cache@v3
with:
paths: |
~/.deno
~/.cache/deno
primary-key: ${{ runner.os }}-deno-${{ hashFiles('**/deps.ts') }}
- uses: actions/cache@v3
with:
paths: |
~/.deno
~/Library/Caches/deno
primary-key: ${{ runner.os }}-deno-${{ hashFiles('**/deps.ts') }}
- uses: actions/cache@v3
with:
paths: |
~\.deno
~\AppData\Local\deno
primary-key: ${{ runner.os }}-deno-${{ hashFiles('**/deps.ts') }}
- uses: actions/cache@v3
with:
paths: |
deps
_build
primary-key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-prefixes-first-match: |
${{ runner.os }}-mix-
- uses: actions/cache@v2
with:
paths: |
~/.cache/rebar3
_build
primary-key: ${{ runner.os }}-erlang-${{ env.OTP_VERSION }}-${{ hashFiles('**/*rebar.lock') }}
restore-prefixes-first-match: |
${{ runner.os }}-erlang-${{ env.OTP_VERSION }}-
- uses: actions/cache@v3
with:
paths: |
~/.cache/go-build
~/go/pkg/mod
primary-key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-prefixes-first-match: |
${{ runner.os }}-go-
- uses: actions/cache@v3
with:
paths: |
~/Library/Caches/go-build
~/go/pkg/mod
primary-key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-prefixes-first-match: |
${{ runner.os }}-go-
- uses: actions/cache@v3
with:
paths: |
~\AppData\Local\go-build
~\go\pkg\mod
primary-key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-prefixes-first-match: |
${{ runner.os }}-go-
We cache the elements of the Cabal store separately, as the entirety of ~/.cabal
can grow very large for projects with many dependencies.
- name: Cache ~/.cabal/packages, ~/.cabal/store and dist-newstyle
uses: actions/cache@v3
with:
paths: |
~/.cabal/packages
~/.cabal/store
dist-newstyle
primary-key: ${{ runner.os }}-${{ matrix.ghc }}-${{ hashFiles('**/*.cabal', '**/cabal.project', '**/cabal.project.freeze') }}
restore-prefixes-first-match: ${{ runner.os }}-${{ matrix.ghc }}-
- uses: actions/cache@v3
name: Cache ~/.stack
with:
paths: ~/.stack
primary-key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
restore-prefixes-first-match: |
${{ runner.os }}-stack-global-
- uses: actions/cache@v3
name: Cache .stack-work
with:
paths: .stack-work
primary-key: ${{ runner.os }}-stack-work-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}-${{ hashFiles('**/*.hs') }}
restore-prefixes-first-match: |
${{ runner.os }}-stack-work-
- uses: actions/cache@v3
name: Cache %APPDATA%\stack %LOCALAPPDATA%\Programs\stack
with:
paths: |
~\AppData\Roaming\stack
~\AppData\Local\Programs\stack
primary-key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
restore-prefixes-first-match: |
${{ runner.os }}-stack-global-
- uses: actions/cache@v3
name: Cache .stack-work
with:
paths: .stack-work
primary-key: ${{ runner.os }}-stack-work-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}-${{ hashFiles('**/*.hs') }}
restore-prefixes-first-match: |
${{ runner.os }}-stack-work-
Note Ensure no Gradle daemons are running anymore when your workflow completes. Creating the cache package might fail due to locks being held by Gradle. Refer to the Gradle Daemon documentation on how to disable or stop the Gradle Daemons.
- uses: actions/cache@v3
with:
paths: |
~/.gradle/caches
~/.gradle/wrapper
primary-key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-prefixes-first-match: |
${{ runner.os }}-gradle-
- name: Cache local Maven repository
uses: actions/cache@v3
with:
paths: ~/.m2/repository
primary-key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-prefixes-first-match: |
${{ runner.os }}-maven-
For npm, cache files are stored in ~/.npm
on Posix, or ~\AppData\npm-cache
on Windows, but it's possible to use npm config get cache
to find the path on any platform. See the npm docs for more details.
If using npm config
to retrieve the cache directory, ensure you run actions/setup-node first to ensure your npm
version is correct.
After deprecation of save-state and set-output commands, the correct way to set output is using ${GITHUB_OUTPUT}
. For linux, we can use ${GITHUB_OUTPUT}
whereas for windows we need to use ${env:GITHUB_OUTPUT}
due to two different default shells in these two different OS ie bash
and pwsh
respectively.
Note It is not recommended to cache
node_modules
, as it can break across Node versions and won't work withnpm ci
- name: Get npm cache directory
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT}
- name: Get npm cache directory
id: npm-cache-dir
shell: pwsh
run: echo "dir=$(npm config get cache)" >> ${env:GITHUB_OUTPUT}
Get npm cache directory
step can then be used with actions/cache
as shown below
- uses: actions/cache@v3
id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
with:
paths: ${{ steps.npm-cache-dir.outputs.dir }}
primary-key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-prefixes-first-match: |
${{ runner.os }}-node-
- name: restore lerna
uses: actions/cache@v3
with:
paths: '**/node_modules'
primary-key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
The yarn cache directory will depend on your operating system and version of yarn
. See https://yarnpkg.com/lang/en/docs/cli/cache/ for more info.
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
paths: ${{ steps.yarn-cache-dir-path.outputs.dir }}
primary-key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-prefixes-first-match: |
${{ runner.os }}-yarn-
The yarn 2 cache directory will depend on your config. See https://yarnpkg.com/configuration/yarnrc#cacheFolder for more info.
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
paths: ${{ steps.yarn-cache-dir-path.outputs.dir }}
primary-key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-prefixes-first-match: |
${{ runner.os }}-yarn-
Esy allows you to export built dependencies and import pre-built dependencies.
- name: Restore Cache
id: restore-cache
uses: actions/cache@v3
with:
paths: _export
primary-key: ${{ runner.os }}-esy-${{ hashFiles('esy.lock/index.json') }}
restore-prefixes-first-match: |
${{ runner.os }}-esy-
- name: Esy install
run: 'esy install'
- name: Import Cache
run: |
esy import-dependencies _export
rm -rf _export
...(Build job)...
# Re-export dependencies if anything has changed or if it is the first time
- name: Setting dependency cache
run: |
esy export-dependencies
if: steps.restore-cache.outputs.cache-hit != 'true'
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
with:
paths: ${{ steps.composer-cache.outputs.dir }}
primary-key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-prefixes-first-match: |
${{ runner.os }}-composer-
For pip, the cache directory will vary by OS. See https://pip.pypa.io/en/stable/reference/pip_install/#caching
Locations:
- Ubuntu:
~/.cache/pip
- Windows:
~\AppData\Local\pip\Cache
- macOS:
~/Library/Caches/pip
- uses: actions/cache@v3
with:
paths: ~/.cache/pip
primary-key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-prefixes-first-match: |
${{ runner.os }}-pip-
Replace ~/.cache/pip
with the correct path
if not using Ubuntu.
- uses: actions/cache@v3
if: startsWith(runner.os, 'Linux')
with:
paths: ~/.cache/pip
primary-key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-prefixes-first-match: |
${{ runner.os }}-pip-
- uses: actions/cache@v3
if: startsWith(runner.os, 'macOS')
with:
paths: ~/Library/Caches/pip
primary-key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-prefixes-first-match: |
${{ runner.os }}-pip-
- uses: actions/cache@v3
if: startsWith(runner.os, 'Windows')
with:
paths: ~\AppData\Local\pip\Cache
primary-key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-prefixes-first-match: |
${{ runner.os }}-pip-
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: ubuntu-latest
paths: ~/.cache/pip
- os: macos-latest
paths: ~/Library/Caches/pip
- os: windows-latest
paths: ~\AppData\Local\pip\Cache
steps:
- uses: actions/cache@v3
with:
paths: ${{ matrix.path }}
primary-key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-prefixes-first-match: |
${{ runner.os }}-pip-
Note This requires pip 20.1+
- name: Get pip cache dir
id: pip-cache
run: |
echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
- name: pip cache
uses: actions/cache@v3
with:
paths: ${{ steps.pip-cache.outputs.dir }}
primary-key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-prefixes-first-match: |
${{ runner.os }}-pip-
- name: Set up Python
# The actions/cache step below uses this id to get the exact python version
id: setup-python
uses: actions/setup-python@v2
⋮
- uses: actions/cache@v3
with:
paths: ~/.local/share/virtualenvs
primary-key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-pipenv-${{ hashFiles('Pipfile.lock') }}
For renv, the cache directory will vary by OS. The RENV_PATHS_ROOT
environment variable is used to set the cache location. Have a look at https://rstudio.github.io/renv/reference/paths.html#details for more details.
- name: Set RENV_PATHS_ROOT
shell: bash
run: |
echo "RENV_PATHS_ROOT=${{ runner.temp }}/renv" >> $GITHUB_ENV
- name: Install and activate renv
run: |
install.packages("renv")
renv::activate()
shell: Rscript {0}
- name: Get R and OS version
id: get-version
run: |
cat("##[set-output name=os-version;]", sessionInfo()$running, "\n", sep = "")
cat("##[set-output name=r-version;]", R.Version()$version.string, sep = "")
shell: Rscript {0}
- name: Restore Renv package cache
uses: actions/cache@v3
with:
paths: ${{ env.RENV_PATHS_ROOT }}
primary-key: ${{ steps.get-version.outputs.os-version }}-${{ steps.get-version.outputs.r-version }}-${{ inputs.cache-version }}-${{ hashFiles('renv.lock') }}
restore-prefixes-first-match: ${{ steps.get-version.outputs.os-version }}-${{ steps.get-version.outputs.r-version }}-${{inputs.cache-version }}-
Caching gems with Bundler correctly is not trivial and just using actions/cache
is not enough.
Instead, it is recommended to use ruby/setup-ruby
's
bundler-cache: true
option
whenever possible:
- uses: ruby/setup-ruby@v1
with:
ruby-version: ...
bundler-cache: true
- uses: actions/cache@v3
with:
paths: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
primary-key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Cache SBT
uses: actions/cache@v3
with:
paths: |
~/.ivy2/cache
~/.sbt
primary-key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }}
- uses: actions/cache@v3
with:
paths: Carthage
primary-key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
restore-prefixes-first-match: |
${{ runner.os }}-carthage-
- uses: actions/cache@v3
with:
paths: Pods
primary-key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
restore-prefixes-first-match: |
${{ runner.os }}-pods-
- uses: actions/cache@v3
with:
paths: .build
primary-key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
restore-prefixes-first-match: |
${{ runner.os }}-spm-
env:
MINT_paths: .mint/lib
MINT_LINK_paths: .mint/bin
steps:
- uses: actions/cache@v3
with:
paths: .mint
primary-key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }}
restore-prefixes-first-match: |
${{ runner.os }}-mint-
bazelisk
does not have be to separately downloaded and installed because it's already included in GitHub's ubuntu-latest
and macos-latest
base images.
- name: Cache Bazel
uses: actions/cache@v3
with:
paths: |
~/.cache/bazel
primary-key: ${{ runner.os }}-bazel-${{ hashFiles('.bazelversion', '.bazelrc', 'WORKSPACE', 'WORKSPACE.bazel', 'MODULE.bazel') }}
restore-prefixes-first-match: |
${{ runner.os }}-bazel-
- run: bazelisk test //...
- name: Cache Bazel
uses: actions/cache@v3
with:
paths: |
/private/var/tmp/_bazel_runner/
primary-key: ${{ runner.os }}-bazel-${{ hashFiles('.bazelversion', '.bazelrc', 'WORKSPACE', 'WORKSPACE.bazel', 'MODULE.bazel') }}
restore-prefixes-first-match: |
${{ runner.os }}-bazel-
- run: bazelisk test //...