Skip to content
Latchkey

Clojure CI slow: ~/.m2, ~/.gitlibs, .cpcache not cached in CI

Clojure builds resolve dependencies into ~/.m2/repository (Maven), git deps into ~/.gitlibs, and cache the computed classpath in .cpcache. If CI does not restore these, every run re-downloads and re-resolves from scratch, adding minutes.

What this error means

CI logs show a full "Retrieving ..." download and classpath rebuild on every run, and total build time is dominated by dependency resolution rather than compilation or tests.

CI
Downloading: org/clojure/clojure/1.11.1/clojure-1.11.1.jar from central
Downloading: ring/ring-core/1.11.0/ring-core-1.11.0.jar from clojars
... (repeats fully on every run because ~/.m2 was not restored)

Common causes

No cache step for the dependency directories

The workflow never restores ~/.m2/repository, ~/.gitlibs, or .cpcache, so each job starts cold.

A cache key that never hits

A key that changes every run (for example including the commit SHA) means the cache is saved but never restored.

How to fix it

Cache all three dependency directories

Restore the Maven repo, git libs, and classpath cache keyed on the dependency files.

.github/workflows/ci.yml
- uses: actions/cache@v4
  with:
    path: |
      ~/.m2/repository
      ~/.gitlibs
      .cpcache
    key: clj-${{ hashFiles('deps.edn', 'project.clj') }}

Prepare dependencies without running code

Use the download-only paths so the cache is populated before tests run.

Terminal
clojure -P        # tools.deps: fetch deps, build .cpcache
lein deps         # Leiningen: fetch into ~/.m2

How to prevent it

  • Cache ~/.m2/repository, ~/.gitlibs, and .cpcache keyed on deps.edn/project.clj.
  • Use a stable hash-based cache key, not one that changes every run.
  • Run clojure -P or lein deps as a dedicated prepare step.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →