Skip to content
Latchkey
Documentation menu

Dependency caching (Fast Cache)

Latchkey Fast Cache saves and restores dependency caches in a single streaming request, with storage in the same region as your runner and zero configuration.

Latchkey Fast Cache (latchkey-dev/cache-action@v1) is a lightweight GitHub Action for saving and restoring dependency caches (node_modules, package registries, build artifacts) on Latchkey managed runners. Repeat runs skip installs your pipeline has already done.

Why it is fast#

  • Cache data moves in a single streaming HTTP request instead of the serial chunk pattern actions/cache@v4 uses: no per-chunk round trips, no temp files.
  • Compression and decompression are multi-threaded (zstd), and uploads and downloads run as parallel transfers.
  • Storage lives in the same region as your runner, so the bytes never travel far.
  • Every save and restore prints its timing in the job log, so you can measure the difference on your own builds.

What caching is worth: a worked example#

The numbers below are illustrative, not a measured benchmark: they show the shape of the win, and your own builds will differ. Picture a Node.js app on latchkey-medium with a ~400 MB node_modules. Without caching, npm ci resolves and downloads everything on every run: call it ~3 minutes (180 s). With a cache hit, the restore is a single streaming download decompressed on the fly, landing in seconds (say ~10 s), and if you skip the install step on a hit (the workflow example below does exactly that) the 3-minute install disappears; teams that run npm ci anyway see it finish in tens of seconds against the warm node_modules. Call the hit path ~30 s of dependency work instead of 180.

On those assumptions that is roughly 2.5 minutes saved per run, and at 100 runs a week it works out to about 250 runner-minutes a week, a little over four hours. Caching does not help every run: a cold key after a lockfile change still pays the full install plus the save (~195 s here), slightly worse than no cache at all; the payoff is every hit that follows.

Illustrative time per run (s)
No cache180s
Cache hit~30s
Cache miss (new lockfile)~195s

Add it to a workflow#

Add two steps: one with action: restore and one with action: save. Each takes a key and one or more path entries (newline or space separated; ~ is supported). The restore step exposes a cache-hit output so you can skip install steps when the cache lands.

.github/workflows/ci.yml
jobs:
  build:
    runs-on: latchkey-medium
    steps:
      - uses: actions/checkout@v4

      - name: Restore dependencies
        id: cache
        uses: latchkey-dev/cache-action@v1
        with:
          action: restore
          key: deps-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
          path: node_modules

      - name: Install dependencies
        if: steps.cache.outputs.cache-hit != 'true'
        run: npm ci

      - name: Save dependencies
        uses: latchkey-dev/cache-action@v1
        with:
          action: save
          key: deps-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
          path: node_modules

Switching from actions/cache#

actions/cache@v4

  • Serial chunked transfers with per-chunk round trips
  • Works on any runner
  • Inputs: path, key, restore-keys

latchkey-dev/cache-action@v1

  • One streaming request per save or restore
  • Storage pre-provisioned, same region as the runner
  • The same inputs carry over: switching is a one-line change

Safe defaults#

  • A restore failure never fails the job: you get a warning, cache-hit reads false, and the run continues.
  • Save is skipped automatically when the key already exists, so identical caches are never re-uploaded.
  • Caches are isolated per organization and automatically versioned by operating system; encode finer isolation (like OS versions) in your cache key.
  • Cache entries are stored server-side with a 14-day retention, so stale caches age out on their own.

What you see in job logs#

Log lineWhat it tells you
Cache restored in {N}msThe restore completed, and how long it took
Cache saved in {N}msThe save completed, and how long it took
Cache missNo cache existed for the key; cache-hit is false and the job continues
Cache already exists for key=..., skipping saveThe save was skipped because an identical key is already stored

Caching you do not have to find#

The AI Scan detects which caches your project needs and lists them in the proposed runner configuration. The "Get more from Latchkey" section of AI Insight can propose adding Latchkey caching to a workflow as a one-click "Add Latchkey caching" PR, and the Migrate Runners tool can inject cache steps as it moves workflows over. Teams that never hand-tune caching still get it.

For the broader craft - trimming install time, splitting slow suites, parallelizing - the Learn library has a hands-on CI optimization hub with guides you can apply on any runner.

References