Volta: Cache VOLTA_HOME and Avoid Re-downloads in CI
Volta downloads each pinned toolchain into $VOLTA_HOME the first time a shim runs it, so caching that directory across CI runs removes repeated Node/npm downloads.
Volta is lazy: it fetches a toolchain on first use, not at pin time. In CI that means the first job pays the download cost. Caching $VOLTA_HOME amortizes it.
What it does
Volta stores downloaded toolchains under $VOLTA_HOME (default ~/.volta), in tools/image for the binaries and bin for the shims. Once cached, a shim resolves and runs the pinned version with no network access.
Common usage
- uses: actions/cache@v4
with:
path: ~/.volta
key: volta-${{ runner.os }}-${{ hashFiles('**/package.json') }}
- run: |
curl https://get.volta.sh | bash
export VOLTA_HOME="$HOME/.volta"
export PATH="$VOLTA_HOME/bin:$PATH"
node -v # downloads pinned toolchain only if not cachedOptions
| Item | What it does |
|---|---|
| VOLTA_HOME | Root of the install and toolchain cache |
| $VOLTA_HOME/bin | Shim directory that must come first on PATH |
| $VOLTA_HOME/tools/image | Cached node/npm/yarn binaries |
| volta fetch <tool>@<v> | Pre-download a toolchain without running it |
| VOLTA_LOGLEVEL=debug | Verbose output for diagnosing fetches |
In CI
Put $VOLTA_HOME/bin ahead of any system Node on PATH or the system binary shadows the shims. Key the cache on package.json so a pin change invalidates it. volta fetch in a setup step warms the cache deterministically instead of relying on lazy first-use download.
Common errors in CI
"Volta error: Could not download node@..." is a transient network/registry failure during lazy fetch; retry or pre-fetch. "permission denied" writing to $VOLTA_HOME on a restored cache means the cache was saved with different ownership; restore under the same user or chown. If the wrong Node runs, the system Node is earlier on PATH than $VOLTA_HOME/bin.