[[single-version-declarations]]
= Declaring Versions and Ranges

The simplest version declaration is a _simple string_ representing the version to use.
Gradle supports different ways of declaring a version string:

* An exact version: e.g. `1.3`, `1.3.0-beta3`, `1.0-20150201.131010-1`
* A Maven-style version range: e.g. `[1.0,)`, `[1.1, 2.0)`, `(1.2, 1.5]`
** The `[` and `]` symbols indicate an inclusive bound; `(` and `)` indicate an exclusive bound.
** When the upper or lower bound is missing, the range has no upper or lower bound.
** The symbol `]` can be used instead of `(` for an exclusive lower bound, and `[` instead of `)` for exclusive upper bound. e.g `]1.0, 2.0[`
* A _prefix_ version range: e.g. `1.+`, `1.3.+`
** Only versions exactly matching the portion before the `+` are included.
** The range `+` on it's own will include any version.
* A `latest-status` version: e.g. `latest.integration`, `latest.release`
** Will match the highest versioned module with the specified status. See link:{javadocPath}/org/gradle/api/artifacts/ComponentMetadata.html#getStatus--[ComponentMetadata.getStatus()].
* A Maven `SNAPSHOT` version identifier: e.g. `1.0-SNAPSHOT`, `1.4.9-beta1-SNAPSHOT`

[NOTE]
====
Gradle 6.5 supports an alternate, opt-in, behaviour for version ranges.

When an upper bound excludes a version, it also acts as a prefix exclude.
This means that `[1.0, 2.0[` will also exclude all versions starting with `2.0` that are smaller than `2.0`.
For example versions like `2.0-dev1` or `2.0-SNAPSHOT` are no longer included in the range.

Activating the feature preview `VERSION_ORDERING_V2` in `settings.gradle(.kts)` enables this change:
```
enableFeaturePreview("VERSION_ORDERING_V2")
```

This change will become the default in Gradle 7.0.
====

== Version ordering

Versions have an implicit ordering. Version ordering is used to:

* Determine if a particular version is included in a range.
* Determine which version is 'newest' when performing conflict resolution.

Versions are ordered based on the following rules:

* Each version is split into it's constituent "parts":
** The characters `[. - _ +]` are used to separate the different "parts" of a version.
** Any part that contains both digits and letters is split into separate parts for each: `1a1 == 1.a.1`
** Only the parts of a version are compared. The actual separator characters are not significant: `1.a.1 == 1-a+1 == 1.a-1 == 1a1`
* The equivalent parts of 2 versions are compared using the following rules:
** If both parts are numeric, the highest numeric value is **higher**: `1.1` < `1.2`
** If one part is numeric, it is considered **higher** than the non-numeric part: `1.a` < `1.1`
** If both are not numeric, the parts are compared **alphabetically, case-sensitive**: `1.A` < `1.B` < `1.a` < `1.b`
** A version with an extra numeric part is considered **higher** than a version without: `1.1` < `1.1.0`
** A version with an extra non-numeric part is considered **lower** than a version without: `1.1.a` < `1.1`
* Certain string values have special meaning for the purposes of ordering:
** The string `dev` is consider **lower** than any other string part: `1.0-dev` < `1.0-alpha` < `1.0-rc`.
** The strings `rc`, `release` and `final` are considered **higher** than any other string part (sorted in that order): `1.0-zeta` < `1.0-rc` < `1.0-release` < `1.0-final` < `1.0`.
** The string `SNAPSHOT` has **no special meaning**, and is sorted alphabetically like any other string part: `1.0-alpha` < `1.0-SNAPSHOT` < `1.0-zeta` < `1.0-rc` < `1.0`.
** Numeric snapshot versions have **no special meaning**, and are sorted like any other numeric part: `1.0` < `1.0-20150201.121010-123` < `1.1`.

[NOTE]
====
Gradle 6.5 supports an alternate, opt-in, version ordering scheme which special cases more suffixes:

* The string `SNAPSHOT` will be ordered higher than `rc`: `1.0-RC` < `1.0-SNAPSHOT` < `1.0`
* The string `GA` will be ordered next to `FINAL` and `RELEASE`, in alphabetical order: `1.0-RC` < `1.0-FINAL` < `1.0-GA` < `1.0-RELEASE` < `1.0`
* The string `SP` will be ordered higher than `RELEASE`, it remains however lower than an unqualified version, limiting its use to versioning schemes using either `FINAL`, `GA` or `RELEASE`: `1.0-RELEASE` < `1.0-SP1` < `1.0`

Activating the feature preview `VERSION_ORDERING_V2` in `settings.gradle(.kts)` enables this set of changes:
```
enableFeaturePreview("VERSION_ORDERING_V2")
```

These changes will become the default in Gradle 7.0.
====

== Simple version declaration semantics

When you declare a version using the short-hand notation, for example:

.A simple declaration
====
include::sample[dir="snippets/dependencyManagement/declaringDependencies-concreteVersion/groovy",files="build.gradle[tags=required-version]"]
include::sample[dir="snippets/dependencyManagement/declaringDependencies-concreteVersion/kotlin",files="build.gradle.kts[tags=required-version]"]
====

Then the version is considered a <<rich_versions.adoc#sec:required-version,required version>> which means that it should _minimally_ be `1.7.15` but can be upgraded by the engine (optimistic upgrade).

There is, however, a shorthand notation for <<rich_versions.adoc#sec:strict-version,strict versions>>, using the `!!` notation:

.Shorthand notation for strict dependencies
====
include::sample[dir="snippets/dependencyManagement/declaringDependencies-concreteVersion/groovy",files="build.gradle[tags=strict-shorthand]"]
include::sample[dir="snippets/dependencyManagement/declaringDependencies-concreteVersion/kotlin",files="build.gradle.kts[tags=strict-shorthand]"]
====

A strict version _cannot be upgraded_ and overrides whatever transitive dependencies originating from this dependency provide.
It is recommended to use ranges for strict versions.

The notation `[1.7, 1.8[!!1.7.25` above is equivalent to:

* strictly `[1.7, 1.8[`
* prefer `1.7.25`

which means that the engine **must** select a version between 1.7 (included) and 1.8 (excluded), and that if no other component in the graph needs a different version, it should _prefer_ `1.7.25`.

[[sec:declaring_without_version]]
== Declaring a dependency without version

A recommended practice for larger projects is to declare dependencies without versions and use <<dependency_constraints.adoc#sec:adding-constraints-transitive-deps,dependency constraints>> for version declaration.
The advantage is that dependency constraints allow you to manage versions of all dependencies, including transitive ones, in one place.

.Declaring a dependency without version
====
include::sample[dir="snippets/dependencyManagement/declaringDependencies-withoutVersion/groovy",files="build.gradle[tags=dependencies-without-version]"]
include::sample[dir="snippets/dependencyManagement/declaringDependencies-withoutVersion/kotlin",files="build.gradle.kts[tags=dependencies-without-version]"]
====
