---
title: "Cache package downloads and dependency stores"
description: "Restore package-manager downloads or dependency stores while keeping a locked install that validates the requested dependency graph."
url: https://starsling.dev/ci-playbooks/techniques/reuse-package-downloads
canonicalUrl: https://starsling.dev/ci-playbooks/techniques/reuse-package-downloads
---

# Cache package downloads and dependency stores

Restore package-manager downloads or dependency stores while keeping a locked install that validates the requested dependency graph.

## How to choose an approach

Compare the examples by repository setup, prerequisites, and risks before adopting one. Each company implemented this in its own environment; measure each change against your own baseline.

- **[DoorDash](https://starsling.dev/ci-playbooks/doordash#cache-go-modules)**: Use it when Go jobs download modules or rebuild unchanged packages on every run. Check before adopting: Key the cache on go.sum and the toolchain version, and measure restore time against a cold run on your runner.
- **[Linear](https://starsling.dev/ci-playbooks/linear#cache-pnpm-store)**: Use it when pnpm installs repeatedly download the same dependency content. Check before adopting: Keep the install and every check running on a cache hit; the cache shortens the download.
- **[Linear](https://starsling.dev/ci-playbooks/linear#cache-yarn-store)**: Use it when Yarn installs repeatedly fetch the same dependency content. Check before adopting: Point the cache at the actual lockfile, keep frozen installs, and keep untrusted runs from writing caches that privileged jobs restore.
- **[Shopify](https://starsling.dev/ci-playbooks/shopify#cache-native-dependencies)**: Use it when Package-manager caches hit while native dependency setup stays cold. Check before adopting: Cache dependency stores and keep native build outputs out of the cache.
- **[Spotify](https://starsling.dev/ci-playbooks/spotify#bazel-caches)**: Use it when Bazel jobs download toolchains and external dependencies and rebuild every output on each run. Check before adopting: Restore-only pull request runs keep untrusted code from writing shared caches; a disk cache per Bazel version keeps versions apart.
- **[Stripe](https://starsling.dev/ci-playbooks/stripe#use-managed-gradle-cache)**: Use it when Gradle cache maintenance is ad hoc, or builds never reuse cached task outputs. Check before adopting: The source PR changed caching, build flags and emulator ordering together. Measure the cache action on its own, and audit cache paths, trust scope and configuration-cache encryption.
- **[Uber](https://starsling.dev/ci-playbooks/uber#cache-build-inputs)**: Use it when Ephemeral CI jobs repeatedly rebuild the same inputs, or a persistent build process keeps stale state after a checkout changes. Check before adopting: Keep cache validity under the build tool's control and restrict cache writes across trust boundaries. Treat a hung build server as its own problem.

## Apply this technique

````text
Evaluate and apply this CI technique to my repository: Cache package downloads and dependency stores.

Restore package-manager downloads or dependency stores while keeping a locked install that validates the requested dependency graph.

Read the technique and its source-backed company examples: https://starsling.dev/ci-playbooks/techniques/reuse-package-downloads.md

Inspect this repository’s CI workflows, build and test commands, dependencies, and recent run timings. Identify where this technique applies and explain the expected benefit using this repository’s evidence.
Measure a baseline from recent comparable runs: elapsed time, queue time, runner minutes and failures where available. If data is unavailable, say what cannot be measured.
Compare relevant company approaches, checking prerequisites, platform differences and tradeoffs. Rank applicable options by evidence, fit and measurable opportunity; do not present company results as predictions for this repo.
Recommend the smallest safe change, show what checks and fallback paths remain, and ASK ME WHICH CHANGE TO APPROVE BEFORE EDITING ANY FILES.
Only after approval, work on a new feature branch, make one reversible change, and open a reviewable pull request. Never merge or push to a default or protected branch.
Keep required checks, test coverage, deployment and release behavior intact. Validate the change and compare equivalent runs where possible; report limitations and what should be monitored after merge.
````

## How companies used this technique

Read what each company changed and follow the original sources.

### DoorDash: Cache Go modules and build output

The first CI workflow for the project pins Go from go.mod and sets the setup action's cache input explicitly (the action caches by default in the version it uses), which restores downloaded modules and build output on later runs. Tests run with -count=1, so Go executes them every time.

Evidence: Source PR/commit evidence

Use it when: Go jobs download modules or rebuild unchanged packages on every run.

Before applying it: Key the cache on go.sum and the toolchain version, and measure restore time against a cold run on your runner.

[Read more in the DoorDash playbook](https://starsling.dev/ci-playbooks/doordash#cache-go-modules)

[Primary source](https://github.com/doordash-oss/agentic-orchestrator/pull/36)

### Linear: Cache the pnpm store, in the right setup order

Linear’s SDK repository installs pnpm before setup-node and caches the pnpm store in its build, release, schema and dependency workflows, keyed on pnpm-lock.yaml.

Evidence: Source PR/commit evidence

Use it when: pnpm installs repeatedly download the same dependency content.

Before applying it: Keep the install and every check running on a cache hit; the cache shortens the download.

[Read more in the Linear playbook](https://starsling.dev/ci-playbooks/linear#cache-pnpm-store)

[Primary source](https://github.com/linear/linear/pull/1130)

### Linear: Cache Yarn downloads while keeping a locked install

Linear’s Zapier integration enables setup-node’s Yarn cache and installs with yarn install --frozen-lockfile, in its test job and its new release workflow.

Evidence: Source PR/commit evidence

Use it when: Yarn installs repeatedly fetch the same dependency content.

Before applying it: Point the cache at the actual lockfile, keep frozen installs, and keep untrusted runs from writing caches that privileged jobs restore.

[Read more in the Linear playbook](https://starsling.dev/ci-playbooks/linear#cache-yarn-store)

[Primary source](https://github.com/linear/linear-zapier/pull/101)

### Shopify: Cache the native dependencies behind a JavaScript build

The React Native jobs already restored pnpm and Bundler caches, while the Android jobs still downloaded Gradle distributions during each run. Checkout Kit turned on the setup-java Gradle cache, keyed on the Android, React Native and sample-app Gradle and package files.

Evidence: Source PR/commit evidence

Merged 2026-05-21; the Gradle cache is on the default branch. ([Source](https://github.com/Shopify/checkout-kit/pull/182))

Use it when: Package-manager caches hit while native dependency setup stays cold.

Before applying it: Cache dependency stores and keep native build outputs out of the cache.

[Read more in the Shopify playbook](https://starsling.dev/ci-playbooks/shopify#cache-native-dependencies)

[Primary source](https://github.com/Shopify/checkout-kit/pull/182)

### Spotify: Cache Bazel downloads and build outputs

target-determinator's presubmit and release jobs now start with setup-bazel, which caches Bazelisk and downloaded Bazel versions, the external repository cache, and a disk cache for build outputs keyed per tested Bazel version. Pull request runs restore the caches without saving them, so trusted builds on main populate them.

Evidence: Source PR/commit evidence

Use it when: Bazel jobs download toolchains and external dependencies and rebuild every output on each run.

Before applying it: Restore-only pull request runs keep untrusted code from writing shared caches; a disk cache per Bazel version keeps versions apart.

[Read more in the Spotify playbook](https://starsling.dev/ci-playbooks/spotify#bazel-caches)

[Primary source](https://github.com/spotify/target-determinator/pull/15)

### Stripe: Use the ecosystem’s cache integration

Stripe React Native replaced hand-maintained Gradle cache paths with gradle/actions/setup-gradle and built the Android app with --build-cache.

Evidence: Source PR/commit evidence

With full caches, the author measured new-architecture app builds at 2:34 against 8:03 and old-architecture builds at 1:42 against 3:50, across all the PR’s changes. Stripe React Native later moved these tests to another CI system in stripe/stripe-react-native#2137. ([Source](https://github.com/stripe/stripe-react-native/pull/2111))

Use it when: Gradle cache maintenance is ad hoc, or builds never reuse cached task outputs.

Before applying it: The source PR changed caching, build flags and emulator ordering together. Measure the cache action on its own, and audit cache paths, trust scope and configuration-cache encryption.

[Read more in the Stripe playbook](https://starsling.dev/ci-playbooks/stripe#use-managed-gradle-cache)

[Primary source](https://github.com/stripe/stripe-react-native/pull/2111)

### Uber: Persist the build cache between runners

Tango added a persistent Bazel disk cache to its integration job. The same PR runs nested queries in a fresh batch-mode Bazel process and raises the outer request timeout. OPT61 is extended from dependency installs to content-addressed build outputs.

Evidence: Source PR/commit evidence

The PR reports a local pass in 81s and a successful CI integration job in 6m45s. ([Source](https://github.com/uber/tango/pull/219))

Use it when: Ephemeral CI jobs repeatedly rebuild the same inputs, or a persistent build process keeps stale state after a checkout changes.

Before applying it: Keep cache validity under the build tool's control and restrict cache writes across trust boundaries. Treat a hung build server as its own problem.

[Read more in the Uber playbook](https://starsling.dev/ci-playbooks/uber#cache-build-inputs)

[Primary source](https://github.com/uber/tango/pull/219)

## CI optimization is continuous work.

Apply this technique yourself, or use StarSling Runners for faster GitHub Actions and optional agent-driven optimization PRs, which teams on eligible paid plans can turn on.

[Get self-improving CI](https://starsling.dev/products/runners)

## Related techniques

### [Persist compiler output between runs](https://starsling.dev/ci-playbooks/techniques/persist-compiler-cache)

Restore compatible compiler outputs and intermediate objects instead of recompiling unchanged inputs.

2 implementations · 2 companies (OpenAI, Ramp)

### [Bake stable dependencies into runner images](https://starsling.dev/ci-playbooks/techniques/prebuild-runner-images)

Prepare versioned system dependencies and build downloads once in the runner image instead of installing them on every job.

2 implementations · 2 companies (Anthropic, Linear)

### [Cache the directories the build actually uses](https://starsling.dev/ci-playbooks/techniques/cache-real-output-paths)

Align restored and saved cache paths with the tool’s real output directories so the next run can use the cached work.

2 implementations · 2 companies (OpenAI, Uber)

## Company Playbooks

### [Anthropic](https://starsling.dev/ci-playbooks/anthropic)

Run only affected tests

### [DoorDash](https://starsling.dev/ci-playbooks/doordash)

Run build and test in parallel, sharded across CI agents

### [Linear](https://starsling.dev/ci-playbooks/linear)

Benchmark the same job on faster hardware

### [Mastra](https://starsling.dev/ci-playbooks/mastra)

StarSling runners for the slowest test workflow

### [OpenAI](https://starsling.dev/ci-playbooks/openai)

Rank CI fixes by the minutes they save

### [Ramp](https://starsling.dev/ci-playbooks/ramp)

Move a CPU-bound test suite to a faster CPU

### [Shopify](https://starsling.dev/ci-playbooks/shopify)

Let an agent iterate against one CI metric

### [Spotify](https://starsling.dev/ci-playbooks/spotify)

Build arm64 on native arm64 runners

### [Stripe](https://starsling.dev/ci-playbooks/stripe)

Run only the tests a change can reach

### [Uber](https://starsling.dev/ci-playbooks/uber)

Build the merge-queue speculations most likely to be needed

## Related guides

Implementation guides for this technique.

### [Cache workflow dependencies](https://starsling.dev/best-practices/github-actions/cache-dependencies)

Choose dependency cache paths and keys for your package manager.

### [Cut repeated test setup](https://starsling.dev/best-practices/github-actions/cut-repeated-test-setup)

Share expensive setup at the scope your tests need.

### [Share setup steps across jobs](https://starsling.dev/github-actions/optimizations/avoid-duplicated-setup)

Centralize repeated setup definitions and remove duplicate or unused steps.

### [Optimize npm installs](https://starsling.dev/github-actions/optimizations/optimize-npm-install)

Cache npm dependencies and large downloads and remove unused tool installs.

### [Optimize pnpm installs](https://starsling.dev/github-actions/optimizations/optimize-pnpm-install)

Set up the pnpm store cache in the right order and scope recursive commands.
