In Gradle, enable dependency locking so resolved versions are saved to a lock file. In Maven, pin versions with dependencyManagement or a bill of materials and enable the enforcer plugin's dependencyConvergence rule. Either way, builds become repeatable and your scans describe what actually ships.
Why locking matters before a split
Legacy builds often use dynamic versions or let transitive libraries float. Gradle's documentation describes the risk directly: with dynamic versions such as 5.+, the resolved version can change over time, so builds can break unexpectedly. For security, the problem is that the scan you ran on Monday may not describe the build produced on Friday.
Before you extract services, a locked, reproducible build gives you a trustworthy baseline, and the new services start with the same discipline.
Gradle: dependency locking
Gradle explains that dependency locking saves the resolved versions of dependencies to a lock file, so later builds use the same versions and the dependency graph does not change unexpectedly.
- Activate locking for the configurations you want, or for all of them.
- Generate the lock state with Gradle's write locks option, which saves what currently resolves.
- Commit the lock files.
- Update locks deliberately, selectively when possible, as part of a reviewed change.
Check the Gradle guide for the exact commands and lock modes in your version.
Maven: pinning and convergence
Maven has no lock file by default. The usual approach is:
- Use dependencyManagement or a bill of materials to specify one version for each artifact, including transitive ones. The Maven enforcer documentation shows how this pins a version regardless of what transitive paths request.
- Enable the dependencyConvergence rule in the enforcer plugin. It fails the build if two dependencies pull different versions of the same artifact, and prints the paths so you can add an exclusion or a pin.
- Avoid version ranges and snapshot dependencies in release builds.
What to do with the result
| Step | Why |
|---|---|
| Commit lock files or pins | Reviewers see every version change |
| Scan the locked result | Findings match the shipped build |
| Update on a schedule | Locks must not freeze vulnerable versions forever |
| Fail CI on drift | Surprises are caught early |
The trade off
Locking stops silent upgrades, including silent security fixes. That is why you need a routine to update. Many teams use a weekly job that proposes lock updates as pull requests, reviewed like any other change.
Common legacy problems
- Parent POMs from other teams that pin old versions
- Excluded dependencies that were never added back
- Shaded or fat archives that bundle libraries, hiding them from the lock file. Scan the final artifact as well as the build file.
Related: why the same library appears in many versions after a split.
Safeguard's dependency scanning and SBOM generation read resolved dependency data, and policies can flag unpinned versions.
Quick check
Does locking make me safer?
It makes builds repeatable and scans accurate. Safety also needs a routine to update locked versions.
Do fat archives need special handling?
Yes. Libraries bundled inside them may not appear in the lock file, so scan the built artifact too.
Sources
Last reviewed: 19 October 2026.