skip to content

Explain the difference between `require`, `prefer`, and `strictly` inside a `version { }` block, and how `reject` interacts with them.

level: middleimportance: should knowfreq 40%

answer

  1. require = min (default)
  2. prefer = soft tie-breaker
  3. strictly = hard, downgrades, can fail
  4. strictly resets require
  5. reject = blacklist, picks highest survivor

basics

~20 s

require is the minimum acceptable (default); higher is fine. prefer is a soft tie-breaker used only when nothing else decides. strictly is a hard requirement that can downgrade and fail. reject blacklists versions that otherwise qualify.

solid answer

~40 s

Gradle's rich version model has three positive notions and one negative: - **`require(v)`** — the *lowest acceptable* version. Writing `implementation("g:a:1.0")` is sugar for `require("1.0")`; conflict resolution may still pick something higher. - **`prefer(v)`** — a *soft* preference, used only as a tie-breaker when `require` leaves a choice open. It never forces a downgrade and is ignored if a higher version is otherwise selected. - **`strictly(v)`** — a *hard* requirement: the resolved version must satisfy it. It can downgrade and can cause resolution to fail when incompatible with another strict requirement. Setting `strictly` clears any previously set `require`. - **`reject(...)`** — blacklists specific versions/ranges; Gradle then picks the highest *non-rejected* version satisfying the other rules. You often combine them, e.g. `strictly("[1.0, 2.0["); prefer("1.5")` — within the strict range, prefer 1.5 unless forced otherwise.

code

kotlin · 7 lines
kotlin
implementation("com.squareup.okhttp3:okhttp") {
  version {
    strictly("[4.9, 5.0[")
    prefer("4.12.0")
    reject("4.11.0")
  }
}

go deeper

for a junior

Know require is the default minimum and strictly is the hard pin.

for a middle

Cleanly distinguish all four and know strictly resets require and can downgrade.

for a senior

Combine strictly+prefer+reject with because() for precise, documented policies.

for a principal

Standardise rich-version idioms across a platform and explain the trade-offs to other teams.

## The rich version constraint model Gradle treats a version as a small set of rules, not a single string. Inside a declaration or constraint you can open a `version { }` block: ```kotlin implementation("org.example:lib") { version { strictly("[1.2, 1.5]") prefer("1.4") reject("1.3.1") } } ``` ### `require` — the default lower bound `require("1.0")` means "1.0 or anything the graph reasonably resolves to that is >= 1.0". It is the *minimum*. Highest-version-wins conflict resolution operates on top of requires. Plain `"g:a:1.0"` desugars to a require. ### `prefer` — soft tie-breaker `prefer` only matters when, after applying all requires and rejects, more than one version is still acceptable and nothing else decides. It is the gentlest signal: it will not pull a version *down* and it loses to any concrete require/strictly that selects a higher version. Use it to express "if it's a free choice, lean this way". ### `strictly` — hard bound that downgrades `strictly` is the only positive notion that acts as an *upper* bound and can force a **downgrade**. Two incompatible stricts ⇒ resolution failure. Importantly, calling `strictly` **resets** `require` (they're mutually exclusive lower-bound semantics), though you may still pair it with `prefer` inside the strict range. ### `reject` — the negative filter `reject` removes versions (a list or range) from consideration — e.g. a known-bad patch. Gradle then chooses the highest surviving version. `reject` composes with all the above; it doesn't pick a version, it only forbids some. ## Putting it together ```kotlin constraints { implementation("com.squareup.okhttp3:okhttp") { version { strictly("[4.9, 5.0[") // stay on 4.x prefer("4.12.0") // but lean to 4.12 if free reject("4.11.0") // known regression } because("4.x line; avoid 4.11 regression; not ready for 5.x") } } ``` This says: must be a 4.x (≥4.9, <5.0), avoid 4.11.0, and when otherwise free choose 4.12.0.

  • If I set both `require("1.0")` then `strictly("1.3")`, what is the effective constraint?
    Just strictly 1.3 — setting strictly clears the previously set require, since they express incompatible lower-bound semantics.
  • Does `prefer` ever cause a downgrade?
    No. prefer is a soft tie-breaker; it only chooses among otherwise-acceptable versions and never lowers a version that a require/strictly already selected higher.

saying these in an interview costs you the question

  • Claiming prefer can force a downgrade.
  • Thinking require is an exact pin rather than a minimum.
  • Saying reject selects a version (it only forbids).

context