Preventing Build Drift in Legacy Projects with Bower --save-exact
Learn how to use the --save-exact flag in Bower to prevent unintended dependency upgrades and ensure deterministic builds in legacy frontend projects.
04 Jun 2026, 09:39 UTC

The Problem: Non-Deterministic Frontend Builds
Legacy frontend projects that rely on Bower often face "it works on my machine" failures. By default, Bower records dependencies in bower.json using semantic versioning (semver) ranges, such as ^3.7.1. When a new developer clones the repository or CI runs a fresh install, Bower may resolve a newer minor or patch release than the one used originally. In older codebases, even a small patch can change CSS behavior or break a JavaScript API, and the root cause is hard to trace because the dependency manifest looks unchanged.
Bower does not generate a lockfile like package-lock.json or yarn.lock. Without one, bower.json is the only source of truth. If it contains ranges, the build is not deterministic, and two clean installs can produce different files in bower_components.
Pinning Versions with --save-exact
The --save-exact flag tells Bower to write the literal installed version into bower.json instead of a semver range. For example, installing jQuery with this flag records "jquery": "3.7.1" rather than "^3.7.1". This pins the top-level dependency so every environment fetches the same version, approximating lockfile behavior for the manifest itself.
Worked Example: Pin jQuery
Run this command from the project root, where bower.json is located. You need write permission for bower.json and the bower_components directory.
bower install jquery#3.7.1 --save-exact
Expected result: Bower downloads jQuery 3.7.1 into bower_components and updates bower.json. Risk: if the registry entry for 3.7.1 is replaced or corrupted, Bower still downloads that content because it only checks the version number, not a package hash.
Verification Steps
- Open bower.json and confirm the dependencies object contains "jquery": "3.7.1" without a caret or tilde prefix.
- Delete the bower_components folder and run bower install. Confirm the restored copy is still version 3.7.1.
- Run bower info jquery to verify the registry lists the pinned version.
Trade-offs and Limitations
Pinning removes automatic updates. You will not receive security patches or bug fixes unless you manually run bower install jquery#3.8.0 --save-exact again, substituting the version you actually need. With many dependencies, keeping bower.json current becomes tedious, and pull requests can accumulate version churn.
This flag does not protect against registry tampering or corrupted packages. It only controls the version string stored locally. Bower is also officially unmaintained as of 2018, so new projects should avoid it entirely.
Private Registry Consideration
Teams can point Bower at a private registry using .bowerrc. The --save-exact flag works the same way with custom registries, but it does not add integrity verification. A private registry can reduce the risk of a public package being replaced or corrupted, though it introduces its own maintenance burden.
Migration Path
If you plan to move to npm or Yarn, pin every Bower dependency first with --save-exact. This creates a known-good baseline that you can map to modern package equivalents without accidentally upgrading libraries during the transition.
To return a dependency to a range, edit bower.json manually, replacing the exact version with a prefix such as ^3.7.1, then run bower install.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.