I’ve been thinking more about dependency updates in JavaScript projects now that AI agents are part of the workflow.
JavaScript makes it really easy to install packages. That is part of what makes the ecosystem useful. But now that more of us are using AI agents, it is also easy for a package to get added because the agent decided it needed one.
I don’t want an agent installing dependencies unless I ask for it.
And if we do add one, I want it pinned.
One caveat: I’m mostly talking about apps I deploy.
For reusable libraries, I would loosen runtime dependency ranges. Those packages need to live inside someone else’s dependency graph.
Peer dependencies should stay broad. Dev dependencies are still fine to pin.
For npm projects, I would start with this:
# .npmrc
save-exact=true
package-lock=true
Then CI should use:
npm ci
Those are doing different jobs.
save-exact=true handles the install side. When a package gets added, it saves the exact version.
{
"dependencies": {
"some-package": "1.2.3"
}
}
Not a version range like this:
{
"dependencies": {
"some-package": "^1.2.3"
}
}
npm ci is the CI side. It installs from the lockfile and fails if the lockfile and package.json do not match.
Just install what was already committed.
This does not make a project secure by itself. If I pin a bad version, I still pinned a bad version.
But it does remove some randomness.
If a dependency changes, I want to see that change in the PR. I want the package name, the version, and the lockfile diff sitting there where someone can review it.
The other thing I have been thinking about is timing.
Pinning helps after a version is selected. It does not help if I install a malicious package five minutes after it was published.
So I like the idea of adding a cooldown.
pnpm does this at the resolver level. As of v11, it waits a day by default before resolving newly published packages. You can also make that longer:
# pnpm-workspace.yaml
minimumReleaseAge: 20160 # two weeks
npm added this natively too. As of 11.10.0 you can set a cooldown in .npmrc:
# .npmrc
min-release-age=14 # days
Note the unit is days here, not minutes like pnpm.
Renovate can do something similar for npm updates.
Two weeks feels like the sweet spot to me. I tend to do dependency updates about once a month anyway, so the cooldown costs me almost nothing. I was not going to be first in line for a release regardless.
It will not catch everything. But it does help with the noisy cases where a bad version gets published, noticed, and removed quickly. If that all happens within a few days, the cooldown keeps me from ever installing it.
For Renovate, I would rather have dependency updates happen in their own PRs.
This would usually live in renovate.json at the root of the repo.
Something like this:
{
"extends": ["config:recommended"],
"dependencyDashboard": true,
"rangeStrategy": "pin",
"internalChecksFilter": "strict",
"lockFileMaintenance": {
"enabled": true,
"schedule": ["before 4am on the first day of the month"]
},
"packageRules": [
{
"matchDatasources": ["npm"],
"minimumReleaseAge": "14 days"
}
]
}
One note: this config assumes an app. rangeStrategy: "pin" pins everything, which is the opposite of what I’d want in a reusable library.
Renovate keeps dependency updates in their own PRs instead of letting them get mixed into normal feature work.
Then I can review the diff and let CI run.
For an app repo, I would also put this directly into the AI rules for the repo.
For Cursor, maybe something like this:
---
description: Dependency security rules
alwaysApply: true
---
# Dependency management
Do not install, remove, or upgrade dependencies unless the developer explicitly asks.
Before suggesting a new dependency:
1. Explain why the existing codebase cannot solve the problem.
2. Prefer built-in APIs or existing dependencies.
3. Ask for approval before changing package.json.
If the developer approves a dependency:
1. Install an exact version.
2. Do not use latest, ^, ~, >, or *.
3. Update the lockfile through the package manager.
4. Do not hand-edit lockfiles.
Same idea for Claude Code:
## Dependency rules
- Do not install npm packages unless explicitly asked.
- Do not choose dependencies on your own.
- Prefer built-in APIs and existing project dependencies.
- If a package is approved, install an exact version.
- Never use latest, caret ranges, tilde ranges, or wildcard ranges.
- Use npm ci for clean installs.
- Do not hand-edit package-lock.json.
Open source is awesome, but we just need to be careful these days.
-Armin