'How to cache yarn packages in GitHub Actions
I am using GitHub Actions to build my TypeScript project. Everytime I run action I am waiting 3 minutes for all dependencies to get installed.
Is there way to cache yarn dependencies, so build time will be faster?
I tried this:
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install yarn
run: npm install -g yarn
- name: Install project dependencies
run: yarn
but build time is still same.
Solution 1:[1]
As mentioned in the comment next to the id
field for the caching step:
Use this to check for
cache-hit
(steps.yarn-cache.outputs.cache-hit != 'true'
)
You're missing a conditional if
property that determines whether the step should be run:
- name: Install yarn
run: npm install -g yarn
- name: Install project dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true' # Over here!
run: yarn
P.S. You should probably use the Setup NodeJS GitHub Action that additionally sets up Yarn for you:
- uses: actions/setup-node@v1
with:
node-version: '10.x' # The version spec of the version to use.
See the action.yml
file for a full list of valid inputs.
EDIT: As it turns out, Yarn is included in the list of software installed on the GitHub-hosted Ubuntu 18.04.4 LTS (ubuntu-latest
/ubuntu-18.04
) runner, so there's no need to include a step to globally install Yarn.
Solution 2:[2]
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
The caching code above only caches and restores the yarn cache directory, it doesn't cache the node_modules
directory. So if you use this code (@Edric's answer),
- name: Install project dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true' # Over here!
run: yarn
node_modules
is not created and you will receive dependencies not found errors.
Instead, you can use this:
- name: Install project dependencies
run: yarn --prefer-offline
This tells yarn
to always run but use cached downloads (in the cache directory mentioned above) whenever possible instead of downloading from the server.
You can also cache the node_modules
directory directly and skip the installation step when the cache is available. This is actually NOT recommended (see comments). Example:
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache yarn cache
uses: actions/cache@v2
id: cache-yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Cache node_modules
id: cache-node-modules
uses: actions/cache@v2
with:
path: node_modules
key: ${{ runner.os }}-${{ matrix.node-version }}-nodemodules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.node-version }}-nodemodules-
- run: yarn
if: |
steps.cache-yarn-cache.outputs.cache-hit != 'true' ||
steps.cache-node-modules.outputs.cache-hit != 'true'
Solution 3:[3]
As the readme of the github package says:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14'
cache: 'npm' # or yarn
- run: npm install
- run: npm test
Edit:
Turns out that the way the docs were written was very misleading and they updated to make it clear that it doesn't cache the node_modules
folder, but only the global cache directory, as stated in this issue.
Also as stated by Mrchief in the comments:
... you'll still incur the
npm i time
, just save on download time from internet (if the module is in npm cache)
So you should still use this save time from downloading packages from internet, but if you want to cache node_modules
folder, check the other answers where it uses actions/cache.
You should also check Quang Lam answer and it's comments on why you shouldn't cache node_modules
folder.
Solution 4:[4]
This is a 1-liner cache specifically for Yarn: https://github.com/c-hive/gha-yarn-cache
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 12.x
- uses: c-hive/gha-yarn-cache@v1
- name: Install JS dependencies
run: yarn install
- name: Test
run: yarn test
It does caching as recommended by GitHub. Supports Yarn v1 and v2.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | |
Solution 4 |