Safeguard
Supply Chain•

Should tutorials pin dependency versions, and how?

Yes. Tutorials should ship a lockfile and tell readers to install from it, so a sample keeps working and a hijacked release cannot slip in later.

Safeguard Security Team
3 min read

Yes. A tutorial should pin its dependencies and ship the lockfile, then tell readers to install from that file. Pinning keeps the sample working as libraries change, and it stops a newly published, possibly malicious release from arriving silently the next time someone follows the steps.

What pinning means for a tutorial

A range such as ^4.17.0 means "any compatible version". That is convenient for an application you maintain daily and risky for a tutorial that sits untouched for two years. A pin names exact versions. A lockfile records the full dependency tree, including the packages your packages pull in.

The npm documentation says package-lock.json describes the exact tree that was generated, so later installs produce identical trees regardless of intermediate dependency updates. It also says the file is intended to be committed to source repositories.

Install command matters as much as the file

A lockfile only helps if readers use it. According to the npm documentation for npm ci, the project must already have a package-lock.json or npm-shrinkwrap.json, and if the lock and package.json disagree, the command exits with an error instead of updating the lock. It never writes to package.json or the lock files. That is the behaviour a tutorial wants.

For Python, the pip documentation describes hash-checking mode, enabled with --require-hashes. Hashes are listed per requirement in the requirements file, and the documentation says the mode protects against remote tampering and network issues. It is all or nothing: once any requirement carries a hash, hashes are required for all of them.

EcosystemPin fileStrict install command
npmpackage-lock.jsonnpm ci
piprequirements.txt with hashespip install --require-hashes -r requirements.txt

Steps for a tutorial author

  1. Generate the lockfile from a clean environment and commit it with the sample.
  2. Replace npm install in your instructions with npm ci, and explain in one line why.
  3. For Python, produce a requirements file with hashes and install with the strict flag.
  4. Pin the language runtime version in the README, since a runtime change breaks samples too.
  5. Add a dated note at the top: "Tested with these versions on this date." Readers can then judge staleness.
  6. Revisit the tutorial on a schedule. Pinning freezes you in time, so old pins can carry known advisories. Re-run a scan and bump versions deliberately.

The trade-off to state honestly

Pinning is not free. Pinned samples drift out of date, and a pinned vulnerable version is still vulnerable. The goal is controlled change, not no change. A tutorial that is reviewed twice a year with a scan and a version bump beats one that floats on ranges.

Try it yourself

An accurate dependency inventory is what makes a pin review possible.

Click through it at your own pace, or open it full screen.

Safeguard's dependency scanning and SBOM generation can inventory the versions a sample uses so they can be checked. The free scan is at https://gold.safeguard.sh/scan.

Quick check

Is npm install different from npm ci for readers?

Yes. According to the npm documentation, npm ci requires an existing lockfile and errors if it disagrees with package.json, rather than changing it.

Does pinning make a tutorial secure?

No. It makes change predictable. You still need to scan the pinned versions and update them on a schedule.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.