Optimizing Build Times in CircleCI with Targeted Caching
Learn how to design precise cache keys, restore and save caches in the same job, and monitor hit ratios to cut CircleCI build times while avoiding stale dependencies.
29 Oct 2025, 21:39 UTC

Desired Outcome
Reduce the duration of CircleCI jobs by leveraging caching for dependencies, while ensuring that cached artifacts stay fresh and do not cause build failures.
Prerequisites
- A CircleCI project already configured with a
config.ymlin the repository root. - Access to modify the
config.ymland commit changes to the branch that triggers builds. - Knowledge of the package manager used (e.g.,
npm,maven,pip) and the location of its cache directory. - Optional: a CircleCI API token if you plan to query cache statistics programmatically.
Procedure
Follow these steps to add a robust caching strategy to a single job. Keeping restore_cache and save_cache in the same job guarantees that the cache key used for restoring matches the one used for saving.
- Define a cache key
Combine project name, lock‑file hash, and environment to capture changes that affect dependencies.
cache_key: <<PROJECT_NAME>>-{{ checksum "package-lock.json" }}-{{ env.CI_OS }}Replace
<<PROJECT_NAME>>with a literal string or an environment variable that uniquely identifies the project. - Restore the cache before installing dependencies
steps: - restore_cache: keys: - <<PROJECT_NAME>>-{{ checksum "package-lock.json" }}-{{ env.CI_OS }} - <<PROJECT_NAME>>-{{ checksum "package-lock.json" }} - <<PROJECT_NAME>>-{{ env.CI_OS }} - <<PROJECT_NAME>> - run: npm ci # or mvn dependency:go-offline, pip install -r requirements.txt, etc.The job will log
Cache hitorCache missbefore the dependency install step. - Run the build and tests
- run: npm test # or your test command - Save the updated cache
- save_cache: key: <<PROJECT_NAME>>-{{ checksum "package-lock.json" }}-{{ env.CI_OS }} paths: - node_modules # adjust for your package managerOnly the directories that changed during the install phase should be cached to keep the cache lightweight.
Expected Checks
- Inspect the job log for a clear
Cache hitorCache missmessage immediately before the dependency install step. - Compare the duration of the dependency install step between a fresh checkout and a cached run; a reduction of at least 30 % indicates effective caching.
- Verify in the CircleCI UI that the cache size corresponds to the expected size of
node_modules(or other cache directory). Excessive growth may signal a mis‑configured key or path.
Recovery Options
- Cache Miss on Critical Step
If the job logs a cache miss but still completes quickly, the cache key may be too specific. Consider adding a fallback key that omits the lock‑file hash:
keys: - <<PROJECT_NAME>>-{{ env.CI_OS }} - <<PROJECT_NAME>> - Stale Dependencies Detected
When a build fails after a cache hit, run a clean build by disabling caching for that job (remove
restore_cacheandsave_cache) to force fresh dependency resolution. If the build succeeds, regenerate the cache with the new dependencies. - Cache Size Exceeds Budget
Prune the cached directory or adjust the
pathslist to exclude large, rarely used artifacts. Usecircleci cache deletevia the API to remove obsolete caches if necessary.
By following this focused workflow—defining precise keys, restoring before installs, saving after, and monitoring hit ratios—you can reliably cut CircleCI build times while avoiding the pitfalls of stale or bloated caches.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.