Built and run by one person.

How do I pin dependencies so they actually stay pinned?

Pinning fails quietly, so it takes three layers plus one people forget.

Why one layer is not enough. Without a lockfile, every install resolves ranges to whatever the registry returns now, so two installs of the same package.json produce two different builds. Even with a lockfile, the default npm install / pnpm install will silently update it when package.json allows a newer version. A caret (^1.2.3) or tilde (~1.2.3) range is the leak path, and pnpm add somepkg writes a caret range by default, so one casual add on a laptop quietly widens a transitive dep you never reviewed.

The three layers: (1) commit the lockfile and treat it as authoritative; (2) use the frozen install command in CI (pnpm install --frozen-lockfile or npm ci) so it refuses to update and fails loud on drift; (3) use exact pins in package.json and set save-prefix= in .npmrc so future adds write 1.2.3, not ^1.2.3. That last setting is what makes the discipline durable - without it every future pnpm add reintroduces a caret and your pinning silently degrades. Direct pins stop package.json drifting; the lockfile stops transitive deps drifting. Neither alone is enough.

The layer people forget: pin the package manager itself. Every other control (cooldown, postinstall blocking, frozen lockfile) is enforced by your package manager. If pnpm itself is compromised, the malicious pnpm simply ignores your .npmrc cooldown and runs whatever postinstalls it likes. Pinning every dependency exactly while running pnpm@latest is a hole big enough to drive a truck through - the same shape as pinning every Python package with pip freeze but installing pip via curl | sh. Pin it in two places: "packageManager": "pnpm@X.Y.Z" in package.json, and an exact version in your install command (npx --yes pnpm@X.Y.Z install --frozen-lockfile). Use an aged version, not the latest, and upgrade it deliberately like any other dependency.

Related: https://www.tigzig.com/agents-faq/should-i-pin-to-the-latest-version. Full items with code: https://www.tigzig.com/security/supply.

← All Agents FAQ