Not using yarn ? see the corresponding pnpm action gist
While @setup/node has a built-in cache parameter for popular package managers, it discards the cache on every lock file update. This composite action allows to run install with (almost always) warm cache. Depending on repo usage, that might reduces the monthly ci-time and decrease the carbon emissions. See also actions/setup-node#325.
Based on the nextjs-monorepo-example. A cold cache install on the ci is more than 2 minutes. With warmed cache: 1 minute. Crafted from benchmarks results in https://gist.github.com/belgattitude/0ecd26155b47e7be1be6163ecfbb0f0b. Depending on repo (renovatebot...), the slight complexity increase in ci setup might worth it.
.
└── .github
├── actions
│ └── yarn-nm-install/action.yml (composite action)
└── workflows
└── ci.yml (uses: ./.github/actions/yarn-nm-install)
Create a file in .github/actions/yarn-nm-install/action.yml
and paste
########################################################################################
# "yarn install" composite action for yarn 2/3/4+ and "nodeLinker: node-modules" #
#--------------------------------------------------------------------------------------#
# Cache: #
# - Downloaded zip archive (multi-arch, preserved across yarn.lock changes) #
# - Yarn install state (discarded on yarn.lock changes) #
# References: #
# - bench: https://gist.github.com/belgattitude/0ecd26155b47e7be1be6163ecfbb0f0b #
# - vs @setup/node: https://github.com/actions/setup-node/issues/325 #
########################################################################################
name: 'Yarn install'
description: 'Run yarn install with node_modules linker and cache enabled'
inputs:
skip-prisma-postinstall-generate:
description: 'Avoid prisma to automatically generate schema on postinstall'
required: false
default: 'false'
runs:
using: 'composite'
steps:
- name: Expose yarn config as "$GITHUB_OUTPUT"
id: yarn-config
shell: bash
run: |
echo "CACHE_FOLDER=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
# Yarn rotates the downloaded cache archives, @see https://github.com/actions/setup-node/issues/325
# Yarn cache is also reusable between arch and os.
- name: Restore yarn cache
uses: actions/cache@v3
id: yarn-download-cache
with:
path: ${{ steps.yarn-config.outputs.CACHE_FOLDER }}
key: yarn-download-cache-${{ hashFiles('yarn.lock') }}
restore-keys: |
yarn-download-cache-
# Invalidated on yarn.lock changes
- name: Restore yarn install state
id: yarn-install-state-cache
uses: actions/cache@v3
with:
path: .yarn/ci-cache/
key: ${{ runner.os }}-yarn-install-state-cache-${{ hashFiles('yarn.lock', '.yarnrc.yml') }}
- name: Install dependencies
shell: bash
run: |
yarn install --immutable --inline-builds
env:
# CI optimizations. Overrides yarnrc.yml options (or their defaults) in the CI action.
YARN_ENABLE_GLOBAL_CACHE: 'false' # Use local cache folder to keep downloaded archives
YARN_NM_MODE: 'hardlinks-local' # Hardlinks-(local|global) reduces io / node_modules size
YARN_INSTALL_STATE_PATH: .yarn/ci-cache/install-state.gz # Very small speedup when lock does not change
# Other environment variables
HUSKY: '0' # By default do not run HUSKY install
PRISMA_SKIP_POSTINSTALL_GENERATE: ${{ inputs.skip-prisma-postinstall-generate }}
To use it in the workflows
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: 📥 Monorepo install
uses: ./.github/actions/yarn-nm-install
# .yarnrc.yml
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.0.0-rc.24.cjs # or v3...
On install, when only few deps changed
Cost of action/cache compression