GitLab NPM Caching

I am trying to understand if the npm directory is being cached and used properly.

As per documentation I used the cache in the following way.

image: docker:latest

stages:
  - test
  - build
  - deploy


cache: # Cache modules using lock file
  key:
    files:
      - package-lock.json
  paths:
    - .npm/

unit-tests:
  image: node:18
  stage: test

  before_script:
    - npm ci --cache .npm --prefer-offline

  script:
    - npm run test

e2e-tests:
  image: cypress/browsers:node-20.14.0-chrome-126.0.6478.114-1-ff-127.0.1-edge-126.0.2592.61-1
  stage: test
  before_script:
    - npm ci --cache .npm --prefer-offline
  script:
    - npm start &
    - npx cypress run

This is a log snippet from one of the two jobs

Restoring cache
00:02
Checking cache for 0_package-lock-0604536a64d1df83b173a05a97xxx82aaa2db-non_protected...
No URL provided, cache will not be downloaded from shared cache server. Instead a local version of cache will be extracted. 
Successfully extracted cache
Executing "step_script" stage of the job script
01:18
Using docker image sha256:d20ad64e1dc926ca4c331077507a8213b48abc02a332b7b8071bc48921a831b3 for cypress/browsers:node-20.14.0-chrome-126.0.6478.114-1-ff-127.0.1-edge-126.0.2592.61-1 with digest cypress/browsers@sha256:3fa039f39d60dd196a74f7eb6944ef18f17b94b1de18f9ace03e61cf876114b5 ...
$ npm ci --cache .npm --prefer-offline
npm warn deprecated inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated npmlog@5.0.1: This package is no longer supported.
npm warn deprecated rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
npm warn deprecated are-we-there-yet@2.0.0: This package is no longer supported.
npm warn deprecated glob@7.2.3: Glob versions prior to v9 are no longer supported
npm warn deprecated gauge@3.0.2: This package is no longer supported.
npm warn deprecated mumath@3.3.4: Redundant dependency in your project.
npm warn deprecated subscriptions-transport-ws@0.9.19: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws    For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md
npm warn deprecated core-js@2.6.12: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
> ui@0.1.0 prepare
> husky
added 1476 packages, and audited 1477 packages in 1m
363 packages are looking for funding
  run `npm fund` for details
found 0 vulnerabilities

It states that the cache is being successfully extracted but I still think that npm ci is running again instead of using the cache.

What could I be doing wrong?

  1. Package-Lock Hash Mismatch:
  • The cache key (0_package-lock-0604536a64d1df83b173a05a97xxx82aaa2db-non_protected ) depends on the package-lock.json hash.
  • If your package-lock.json has changed since the cache was created, the cache won’t be used (even though it’s extracted).
  1. Package Update During npm ci:
  • Even with --prefer-offline , npm ci might still perform some checks or updates, especially if certain package versions are explicitly locked in package-lock.json .

Verification and Debugging Steps:

  1. Compare package-lock.json:
  • Before the cache extraction (Restoring cache message), check your local package-lock.json hash.
  • After the extraction (Successfully extracted cache message), check the package-lock.json hash again.
  • If the hashes differ, the cache won’t be used because the dependencies have changed.
  1. Review npm ci Output:
  • Look for any messages indicating updates during npm ci .
  • Lines like “downloading” or “updating” signify packages being downloaded, not solely from the cache.

Optimization Options:

  1. Strict Versioning in package-lock.json:
  • Consider using npm ci --only=prod in your before_script to strictly follow the exact dependencies specified in package-lock.json , avoiding any updates if the versions are locked.