[[resolution-strategy-safety-nets]]
= Preventing accidental dependency upgrades

In some situations, you might want to be in total control of the dependency graph.
In particular, you may want to make sure that:

- the versions declared in a build script actually correspond to the ones being resolved
- or make sure that dependency resolution is reproducible over time

Gradle provides ways to perform this by configuring the resolution strategy.

[[fail-version-conflict]]
== Failing on version conflict

There's a version conflict whenever Gradle finds the same module in two different versions in a dependency graph.
By default, Gradle performs _optimistic upgrades_, meaning that if version `1.1` and `1.3` are found in the graph, we resolve to the highest version, `1.3`.
However, it is easy to miss that some dependencies are upgraded because of a transitive dependency.
In the example above, if `1.1` was a version used in your build script and `1.3` a version brought transitively, you could use `1.3` without actually noticing.

To make sure that you are aware of such upgrades, Gradle provides a mode that can be activated in the resolution strategy of a configuration.
Imagine the following dependencies declaration:

.Direct dependency version not matching a transitive version
====
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/groovy",files="build.gradle[tags=dependencies]"]
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/kotlin",files="build.gradle.kts[tags=dependencies]"]
====

Then by default Gradle would upgrade `commons-lang3`, but it is possible to _fail_ the build:

.Fail on version conflict
====
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/groovy",files="build.gradle[tags=fail-on-version-conflict]"]
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/kotlin",files="build.gradle.kts[tags=fail-on-version-conflict]"]
====

[[reproducible-resolution]]
== Making sure resolution is reproducible

There are cases where dependency resolution can be _unstable_ over time.
That is to say that if you build at date D, building at date D+x may give a different resolution result.

This is possible in the following cases:

- dynamic dependency versions are used (version ranges, `latest.release`, `1.+`, ...)
- or _changing_ versions are used (SNAPSHOTs, fixed version with changing contents, ...)

The recommended way to deal with dynamic versions is to use <<dependency_locking.adoc#dependency-locking,dependency locking>>.
However, it is possible to prevent the use of dynamic versions altogether, which is an alternate strategy:

.Failing on dynamic versions
====
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/groovy",files="build.gradle[tags=fail-on-dynamic]"]
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/kotlin",files="build.gradle.kts[tags=fail-on-dynamic]"]
====

Likewise, it's possible to prevent the use of changing versions by activating this flag:

.Failing on changing versions
====
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/groovy",files="build.gradle[tags=fail-on-changing]"]
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/kotlin",files="build.gradle.kts[tags=fail-on-changing]"]
====

It's a good practice to fail on changing versions at release time.

Eventually, it's possible to combine both failing on dynamic versions and changing versions using a single call:

.Failing on non-reproducible resolution
====
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/groovy",files="build.gradle[tags=fail-on-unstable]"]
include::sample[dir="snippets/userguide/dependencyManagement/managingTransitiveDependencies/resolutionStrategy/kotlin",files="build.gradle.kts[tags=fail-on-unstable]"]
====
