# Dependency and lockfile discipline ## Two npm realities CI runners and the API Docker image use the node version pinned in `.nvmrc` (node 20.19.4 with npm 10.8.2). A developer machine can run a newer npm (for example npm 11). npm 10 and npm 11 resolve wildcard or range dependencies differently at the same place in the dependency tree, and each npm's platform-optional binary selection is not portable to a lockfile regenerated by the other npm. A lockfile that passes `npm ci` under one npm major version can fail it under the other with either an "Invalid: lock file's ... does not satisfy" error or missing platform-optional binaries (for example `@next/swc-linux-x64-gnu` breaking `next build`, `@rollup/rollup-linux-x64-gnu` breaking the API Docker `tsup` build, or a missing `lightningcss` variant breaking local `npm ci`). ## Pin wildcard-range dependencies with root overrides When a transitive dependency declares a wildcard or wide range (for example `react-native-worklets` depending on `@react-native/metro-config: "*"`), pin the exact version the app needs in the root `package.json` `overrides` block rather than leaving it to whichever npm resolved the lockfile last: ```json "overrides": { "rollup": "4.54.0", "react-native": "0.85.3", "expo": "~56.0.0", "@react-native/metro-config": "0.85.3" } ``` ## Pin platform-optional binaries that must travel with the framework version `apps/web/package.json` pins the `@next/swc` linux and darwin binaries as direct `optionalDependencies` so npm does not have to infer them per platform: ```json "optionalDependencies": { "@next/swc-linux-x64-gnu": "15.5.24", "@next/swc-linux-x64-musl": "15.5.24", "@next/swc-darwin-arm64": "15.5.24" } ``` These versions must be bumped together with any `next` version bump, or the pinned binaries will drift from the framework version and `npm ci` or `next build` can fail on the platform that needs the stale binary. ## Validate a regenerated lockfile both ways After changing `overrides` or any dependency version, regenerate `package-lock.json` and validate it under both npm majors before committing: ```bash # Local npm (matches this machine's npm major) npm ci npm run verify:fast # The CI/Docker npm major, emulated on Apple Silicon docker run --rm --platform linux/amd64 -v "$PWD:/repo" -w /repo node:20.19.4 npm ci ``` The `--platform linux/amd64` flag is mandatory on Apple Silicon: without it, Docker runs the arm64 image and the platform-binary check proves nothing. ## After any bypassed push Pushes to `staging` bypass required status checks. After any such push, check `gh run list --branch staging` to confirm CI is actually green rather than assuming it ran and passed. Do not pipe `npm` commands through `tail` when diagnosing a lockfile or build failure; it can swallow the command's exit code and the detail needed to find the root cause.