Dsh plugin version pinning is the difference between a plugin set you can rebuild and one you can only describe. This guide covers lockfile best practices dsh teams can actually follow, how to pin plugin version range without freezing yourself out of patches, what caret vs tilde plugin version notation really does inside a dsh manifest, and the few steps that make a reproducible plugin install possible on a fresh machine.
Why exact versions beat ranges
A range is a statement about the future, and the future is where plugin risk lives. When your manifest says any 2.x is acceptable, you are agreeing in advance to whatever the maintainer publishes next, including the release that changes an install script or quietly adds a dependency. The plugin you scored last month is not the plugin you get today.
Exact versions turn that around. The score in the index is attached to a version, the advisory is attached to a version, and your install should be attached to the same version. Every link in that chain is only as strong as the loosest one, and an unpinned manifest is always the loosest one.
Lockfile best practices dsh teams can follow
- Commit the lockfile. A lockfile that only exists on one laptop is a note to yourself, not a build input.
- Review lockfile diffs on their own. A diff that changes forty versions is a conversation, not a rubber stamp.
- Record the plugin, the exact version, and the score you saw when you approved it. Three fields, and they answer the question you will actually be asked six months later.
- Re-pin deliberately. Bump one plugin, run the scan on the new version, then commit. Bulk refreshes hide the one change that mattered.
- Keep the previous lockfile. The fastest rollback is a file you already have, and [how to update dsh plugins without breaking your setup](/blog/how-to-update-dsh-plugins-without-breaking-your-setup) walks through that sequence.
How to pin plugin version range
Pinning does not have to mean never moving. The useful middle ground is a bounded range: wide enough for patch fixes, narrow enough that a minor release cannot land without someone looking at it.
| Manifest entry | What installs | When to use it |
|---|---|---|
| 1.4.2 | Only 1.4.2, forever | Production, CI, anything with credentials in reach |
| ~1.4.2 | 1.4.x patches | Plugins with a steady patch cadence and a good score |
| ^1.4.2 | Any 1.x release | Local tooling, never a shared build |
| latest | Whatever exists today | Nothing you would describe as a build |
Caret vs tilde plugin version notation
The two symbols get confused constantly, and the difference is one position in the version number. Tilde holds the last digit you named and lets the final one move; caret holds the first non-zero digit and lets everything after it move.
| Entry | Accepts | Rejects |
|---|---|---|
| ~1.4.2 | 1.4.9 | 1.5.0 |
| ^1.4.2 | 1.9.0 | 2.0.0 |
| ^0.4.2 | 0.4.7 | 0.5.0 |
| 1.4.2 | nothing else | everything else |
The trap sits in the 0.x line. Caret against 0.4.2 behaves like tilde, because a leading zero means the API has not settled. Teams that assume caret always allows minor upgrades get surprised there first.
Getting a reproducible plugin install
- Start from the lockfile, not from a README. A documented install command is a suggestion; the lockfile is a fact.
- Install on a clean machine or container once a quarter. Reproducibility you have never tested is an assumption.
- Verify after installing, not before. Score the version you actually got, because [dependency confusion](/blog/dependency-confusion) and mirror drift both produce a package that matches the name and nothing else.
- Snapshot the config alongside the lockfile. Version pinning without [a config backup](/blog/backup-dsh-plugin-configuration) gets you the right plugin with the wrong settings.
- Gate every version bump, including downgrades. [Allowlists](/blog/setting-up-a-plugin-allowlist-for-your-dev-team) that only run on first install leave the update path open.
A pinned version is a claim about one artefact at one moment. The lockfile is what makes that claim repeatable.
FAQ
- Does pinning stop me getting security fixes? It stops you getting them silently. Fixes still arrive, but they arrive as a reviewable diff instead of an overnight change.
- Should every plugin be pinned exactly? Anything in a shared or automated path, yes. Throwaway local tools can keep a tilde range and save you the churn.
- What if a maintainer stops publishing the version I pinned? That is a decision point, not a bug. Either take the newer version through the normal gate or plan an exit.
- How do I know the version I installed is the version I scored? Re-run the check against the installed version. How that scan works is at /blog/how-install-script-scanning-works.
- Does a lockfile replace the quality score? No. The score tells you whether a version was worth installing; the lockfile tells you that you still have that version.
Every plugin page on dshquality.com shows the versions the score applies to, so pinning to a scored version is a copy away from the index at /. Version movement over time is covered at /blog/dsh-plugin-score-trends-what-a-dropping-score-means, team-wide gates are at /blog/plugin-supply-chain-security-team-enforcement, and the rest of the notes are at /blog.