When centralizing versions, what is the difference between using Maven <properties> for versions versus <dependencyManagement>, and how do they interact in a multi-module project?
answer
- properties = text variable
- dependencyManagement = managed default
- combine: property inside DM
- child can override property
- BOM override via local property
basics
~20 sA <properties> entry like <guava.version>33.2.1</guava.version> is just a reusable string you reference with ${guava.version}; you still write the version everywhere. <dependencyManagement> sets a managed default so child modules can omit the version entirely. Teams often combine both.
solid answer
~40 sThey operate at different layers. A `<properties>` value is a text variable: you define `<x.version>` once and substitute `${x.version}` wherever you need it — but each dependency still carries an explicit <version> tag. `<dependencyManagement>` is a resolution mechanism: it declares managed defaults so child `<dependencies>` can omit <version> and inherit it, and it also overrides transitive versions. The common idiom combines them: put the literal version in a property and reference it from the parent's dependencyManagement, giving you one obvious place to edit while children stay version-free. Properties are inherited by child POMs too, and a child can override a property to locally change a version. BOM import is really dependencyManagement behavior. Choose properties for readability/reuse (including plugin versions and arbitrary config), and dependencyManagement for actually governing what versions resolve.
code
xml · 12 lines<properties>
<guava.version>33.2.1-jre</guava.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
</dependencyManagement>go deeper
Knows ${x.version} is a reusable variable and that DM lets children omit versions.
Can write the property-inside-dependencyManagement idiom correctly.
Explains the layering, inheritance/override rules, and when each is appropriate.
Designs the parent-POM/BOM/property convention org-wide for clean upgrades and tooling (Dependabot) friendliness.
## Two different layers - **<properties>**: a simple key→string map. `<guava.version>33.2.1-jre</guava.version>` defines a variable; `${guava.version}` substitutes it during POM interpolation. It does nothing Maven-specific about dependencies — it's just text reuse, usable for plugin versions, config values, anything. - **<dependencyManagement>**: a Maven resolution feature. It registers managed defaults (version/scope/exclusions) so a child <dependencies> entry can omit the version and inherit it, and it overrides transitive versions during mediation. ## They are complementary, not exclusive A very common parent-POM pattern: ```xml <properties> <guava.version>33.2.1-jre</guava.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>${guava.version}</version> </dependency> </dependencies> </dependencyManagement> ``` Now: - The literal version lives in ONE property (easy to scan/bump, friendly to Dependabot). - Child modules just declare guava with no version and inherit it. ## Inheritance and overrides - **Properties are inherited** by child POMs and can be **overridden** in a child to change the value locally. - **dependencyManagement is inherited** too; a child's own dependencyManagement or a direct <version> overrides the inherited managed version. - Imported BOMs are inlined into your dependencyManagement, and your local management (often property-driven) overrides BOM versions — a frequent way to bump one library above what a BOM ships. ## When to use which - Use **properties** when you want a named, reusable value — especially plugin versions (there's no automatic version inheritance for plugin <dependencies> the way there is for managed deps) and shared config. - Use **dependencyManagement** when you want children to drop the <version> and to govern transitive versions. - Use **both** for the cleanest multi-module setup. ## Pitfall A property alone does NOT let a child omit <version> — you still must write `<version>${x.version}</version>` on each dependency. Only dependencyManagement gives true version-free child declarations.
- Does defining <guava.version> as a property let child modules omit <version>?No. A property is just a variable; each dependency still needs <version>${guava.version}</version>. Only dependencyManagement enables version-free child declarations.
- How do you bump a single library above what an imported BOM provides?Declare that artifact in your own <dependencyManagement> (often via a property) — local management overrides the imported BOM.
- Can a child module override a version property from the parent?Yes — properties are inherited and a child can redefine the property to change the value for that module.
saying these in an interview costs you the question
- Claiming a <properties> entry alone lets children skip <version>.
- Treating properties and dependencyManagement as interchangeable.
- Saying you cannot override a BOM version (you can, via local dependencyManagement).