skip to content

How do profiles override dependencies and plugin configuration, and what risks does this introduce for reproducible builds?

level: principalimportance: should knowfreq 40%

answer

  1. merge into effective model, profile wins
  2. layered, later overrides earlier
  3. non-determinism = works-on-my-machine
  4. prefer properties over dep swaps
  5. pin CI with explicit -P; effective-pom

basics

~20 s

An active profile merges its dependencies, plugin config, and properties into the effective build, overriding base values. The risk is that the same command produces different artifacts depending on which profiles are active, which can break reproducibility and surprise CI.

solid answer

~40 s

When a profile is active Maven merges its `<dependencies>`, `<dependencyManagement>`, `<build>`/`<plugins>` config, `<properties>`, `<repositories>`, and `<modules>` into the effective model — profile values override the base, and multiple active profiles layer in declaration/order with later-applied winning. This is powerful: a `prod` profile can swap a runtime dependency, a `release` profile can add the GPG and source plugins. The danger is **non-determinism**: build output now depends on hidden activation state (a property, the JDK, the OS, a file's presence), so `mvn package` can yield different jars on different machines. Mitigations: prefer property-driven config over swapping dependencies; never put dependency/plugin changes in auto-activated profiles that vary by environment; pin CI invocations with explicit `-P`; verify with `mvn help:active-profiles` and `help:effective-pom`; and avoid OS/file-based activation for anything that affects shipped artifacts.

code

bash · 2 lines
bash
mvn help:active-profiles   # what is active and why
mvn help:effective-pom     # the merged result after profiles applied

go deeper

for a junior

Know an active profile's settings override the base build.

for a middle

Know profiles merge dependencies/plugins/properties into the effective model and later-applied profiles win.

for a senior

Recognize the reproducibility risk and prefer property toggles; pin CI activation and inspect effective-pom.

for a principal

Set governance: artifact-affecting profiles must be explicit, environment auto-activation limited to harmless config, builds verifiably reproducible across machines and CI.

## How overriding works Maven builds an **effective model** by merging the base POM, inherited parent POMs, and every **active** profile. A profile can contribute: - `<properties>` — override scalar values used in filtering and plugin config. - `<dependencies>` / `<dependencyManagement>` — add or override (by `groupId:artifactId:type:classifier`) dependency declarations. - `<build>` → `<plugins>` / `<pluginManagement>` — add plugins or override their configuration and executions. - `<repositories>`, `<modules>`, `<reporting>`. When the same coordinate appears in both base and an active profile, the profile's value wins. With several active profiles, they layer on in order, later application overriding earlier. ## Why this is risky The build output is now a function of **which profiles happened to be active**, and activation can be implicit: - A `<property>` trigger fires because some `-D` or env var was set. - A `<jdk>` or `<os>` trigger fires differently on a teammate's machine. - A `<file><exists>` trigger fires because a generated file is or isn't present. Result: `mvn package` can produce a *different* artifact in CI than on a laptop — a classic "works on my machine" trap, and a supply-chain / reproducibility concern because the dependency set itself can shift. ## Practical mitigations 1. **Prefer properties over structural changes.** Toggling a JDBC URL via `${db.url}` is safe; swapping a dependency per environment changes what's shipped. 2. **Don't auto-activate artifact-affecting profiles.** Keep OS/JDK/file/property auto-activation for harmless things (e.g. enabling a local-only plugin); require explicit `-P` for anything that changes dependencies or shipped output. 3. **Pin CI.** Always pass explicit `-P` (and `!` to suppress unwanted defaults) so CI is deterministic. 4. **Inspect the result.** ```bash mvn help:active-profiles mvn help:effective-pom ``` These reveal exactly what merged in. 5. **Document the profile contract** — which profiles exist, what they change, and which are default — in the repo README. ## Example: a release profile ```xml <profile> <id>release</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-gpg-plugin</artifactId> <executions> <execution> <id>sign</id> <goals><goal>sign</goal></goals> </execution> </executions> </plugin> </plugins> </build> </profile> ``` This is good profile usage: explicit (`-P release`), additive, and only run when releasing.

  • Why is swapping a dependency in an OS-activated profile dangerous?
    The shipped artifact's dependency set then differs by machine OS, breaking reproducibility — a Linux CI build and a Mac dev build could contain different libraries from the identical command.
  • How do you make a profiled build reproducible in CI?
    Pin the active set explicitly with -P (and !-deactivate unwanted defaults), avoid environment-based auto-activation for artifact-affecting changes, and verify with help:active-profiles / help:effective-pom.
  • If two active profiles set the same property, which wins?
    Profiles are applied in order and the later-applied one overrides earlier ones; order depends on declaration/activation, so avoid relying on overlapping profile properties.

saying these in an interview costs you the question

  • Treating profile overrides as fully deterministic regardless of environment.
  • Putting dependency or shipped-artifact changes behind os/jdk/file auto-activation.
  • Not verifying the merged result with help:effective-pom before trusting it.

context