Maven Properties, Profiles, settings.xml, Mirrors, Proxies, Servers, and Environment-Specific Builds: Concepts, Architecture, and Mental Model
Separate repository-owned Maven configuration from environment-owned settings: understand property sources, profile activation, global/user settings, mirrors, proxies, server credential indirection, and the effective build state Maven actually uses.
Learning objectives
- Separate repository-owned Maven state from machine/user/CI environment state before changing either one.
- Identify Maven property families and explain why command-line user properties can override project/profile values.
- Distinguish project, user, and global profiles and explain explicit versus implicit activation.
-
Explain how global/user
settings.xml, mirrors, proxies, servers, and repository IDs affect resolution without belonging in the POM. - Use read-only Help Plugin goals to reveal active profiles, effective settings, effective POM state, and selected property values.
~/.m2, global
settings, shared CI settings, or real credentials are modified.
?. Do not copy
Maven 4-only optional-profile syntax into the Maven 3 lab and assume
identical behavior.
1. The practical problem — one POM, many environments
Chapters 04–07 made Maven itself, the POM, dependencies, lifecycle, and plugins visible. A production build still has another source of state: the environment that invokes the project. Developer laptops, CI agents, and controlled release workers may need different proxy routes, mirror endpoints, authentication material, or explicitly selected build modes. If those differences leak into the POM, the project becomes machine-specific. If they remain hidden in uninspected settings, the build becomes difficult to reproduce.
The goal is not “make every machine identical.” The goal is to establish a contract: portable build intent stays with the project; access policy and secrets stay at controlled environment boundaries; every effective difference is observable.
2. The state stores must remain separate
Maven combines several inputs during model building and repository resolution, but combining them at runtime does not make them the same kind of state.
| State store | Owned by | Typical contents | Should it be committed? |
|---|---|---|---|
pom.xml |
Project | Coordinates, dependencies, plugins, portable properties/profiles | Yes |
.mvn/ |
Project | Wrapper/config/extension state appropriate for the repository | Yes, when intentional and secret-free |
Global settings.xml |
Maven installation/platform image | Organization or installation defaults | Normally managed with the image, not copied into each repo |
User settings.xml |
Developer/CI identity | Mirrors, proxies, server credentials, user profiles | No secrets in source control |
| Environment variables / CI secret injection | Process/CI | Credentials or process-specific selectors | No |
| Local repository | Machine/job | Resolved artifacts, metadata, installed artifacts | No; cache/state, not source of truth |
| Effective POM/settings | Derived evidence | Merged/interpolated active model | Generated evidence, not hand-edited source |
3. Mental model — declared project + environment policy → effective build
Maven first establishes runtime/system/user properties and settings, builds the effective project model with active profiles, and then resolves repositories after mirror/proxy/server policy is applied. This is why a repository URL written in a POM is not necessarily the network endpoint contacted by the build.
flowchart TD POM[pom.xml + project profiles] MVN[.mvn wrapper/config] GS[global settings.xml] US[user/alternate settings.xml] ENV[system + env + CLI user properties] EFF[effective POM + active profiles] SET[effective settings] REPO[declared repository IDs] MIR[mirror/proxy/server policy] END[actual endpoint] POM --> EFF MVN --> EFF GS --> SET US --> SET ENV --> EFF ENV --> SET SET --> EFF EFF --> REPO SET --> MIR REPO --> MIR MIR --> END
Every arrow represents a causal relationship you can inspect: settings change the effective environment, active profiles change the effective POM, and mirrors rewrite repository routing before transport begins.
4. Property sources — name the source before arguing about “precedence”
Maven exposes several property families.
${project.version} comes from the project model;
${settings.offline} comes from settings;
${java.home} is a Java system property;
${env.PATH} exposes an environment variable; plain
${academy.channel} may come from POM/profile properties
or from a command-line user property such as
-Dacademy.channel=cli.
| Source | Example | Operational meaning |
|---|---|---|
| Project model | ${project.version} |
A field in the effective POM. |
POM <properties> |
${academy.channel} |
Portable default owned by the project. |
| Active profile property | ${academy.channel} |
Conditional model contribution; source matters. |
| Settings model | ${settings.localRepository} |
Machine/user settings value. |
| Java system property | ${java.home} |
Property of the JVM running Maven. |
| Environment property | ${env.ACADEMY_REPO_USER} |
Process environment exposed through the
env. prefix.
|
| CLI user property | -Dacademy.channel=cli |
Invocation-level override; treat as high-precedence deliberate input. |
5. Profiles are conditional model fragments, not “environments” by themselves
A profile can contribute properties, dependencies, repositories, plugin configuration, and other model elements. Profiles may live in the project POM, user settings, or global settings. Maven resolves profile activation early; profile effects participate in the effective model. A child does not simply inherit the parent's raw profile definition as another switch.
| Activation style | Example | Risk / use |
|---|---|---|
| Explicit | -Pdev |
Most auditable when the choice is a conscious build input. |
<activeProfiles> in settings |
User/CI-selected profile ID | Useful for controlled environment policy; can be invisible unless inspected. |
activeByDefault |
POM default profile | Convenient, but automatically deactivates when another profile in the same POM becomes active. |
| JDK / OS | Automatic runtime match | Useful sparingly; can make developer/CI behavior diverge. |
| System/CLI property | Activate when a property exists/matches | More explicit when property is supplied deliberately. |
| File exists/missing | Filesystem condition | Powerful but easy to make machine-specific. |
6. What belongs in settings.xml
Maven merges global and user settings, with user settings dominant
where the models overlap. An alternate user settings file may be
selected with -s/--settings; an alternate
global settings file uses
-gs/--global-settings. These are
invocation/environment controls, not POM content.
| Element | Purpose | Security/reproducibility note |
|---|---|---|
localRepository |
Machine-local artifact/install state | Use explicit isolated paths in disposable labs/CI diagnostics. |
servers |
Authentication keyed by server/repository ID | Credentials stay outside POM. |
mirrors |
Rewrite repository destinations by ID/pattern |
Mirror breadth is policy; inspect mirrorOf.
|
proxies |
Network proxy routing/authentication | Environment/infrastructure concern. |
profiles |
User/global conditional properties/repositories | Can modify effective build; always inspect activation. |
activeProfiles |
Always activate named profiles for that settings context | Hidden default if not captured in CI evidence. |
pluginGroups |
Extra groups searched by short plugin prefixes | Executable-code trust boundary from Chapter 07. |
7. Mirrors, repository IDs, and server credential indirection
A mirror does not “add another repository.” It substitutes the
endpoint Maven uses for repositories matched by
mirrorOf. The mirror has its own id.
Maven's settings documentation explicitly states that this mirror ID
is used to pick corresponding credentials from
<servers>. That is why changing only a server ID
can turn a working build into a 401 even when username/password
values did not change.
<mirrors>
<mirror>
<id>corp-mirror</id>
<url>https://repo.example.invalid/maven-virtual</url>
<mirrorOf>external:*</mirrorOf>
</mirror>
</mirrors>
<servers>
<server>
<id>corp-mirror</id>
<username>${env.REPO_USER}</username>
<password>${env.REPO_PASSWORD}</password>
</server>
</servers>
Patterns include exact repository IDs, *,
external:*, external:http:*,
comma-separated expressions, and ! exclusions. Broader
is not automatically safer: * can capture a repository
that a test fixture expected to remain local.
8. Proxy state is transport policy, not dependency identity
A proxy controls how Maven reaches an endpoint; it does not change a
coordinate such as org.example:lib:1.2.3. Keep this
distinction during diagnosis. A 407 proxy-authentication error is
not evidence that the dependency version is wrong. Likewise, adding
a new repository to “fix networking” changes the supply-chain
boundary and is not a harmless network workaround.
9. Read-only inspection before mutation
Use the wrapper and explicit Help Plugin version. Write evidence
outside target/ so a later clean does not
erase it.
mkdir -p evidence
./mvnw -v | tee evidence/maven-version.txt
./mvnw org.apache.maven.plugins:maven-help-plugin:3.5.2:active-profiles -Doutput=evidence/active-profiles.txt
./mvnw org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-settings -Doutput=evidence/effective-settings.xml
./mvnw org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom -Dverbose -Doutput=evidence/effective-pom.xml
./mvnw org.apache.maven.plugins:maven-help-plugin:3.5.2:evaluate -Dexpression=academy.channel -q -DforceStdout
help:effective-settings hides passwords by default. Do
not enable password display for ordinary troubleshooting, and review
any debug/effective-model artifact before sharing it outside the
trusted build context.
10. DevOps operating contract
A robust CI job records wrapper/Maven/JDK identity, the explicit profile selection, the settings source/policy identifier, and the repository/mirror endpoint IDs without printing secrets. The artifact pipeline should be able to answer: Which profile changed the model? Which settings selected the network path? Which server ID supplied authentication? Which properties were invocation overrides?
11. Common misconceptions
| Misconception | Correction |
|---|---|
| “A profile is the deployment environment.” | A profile is a model fragment. Deployment runtime configuration often belongs later, outside the build artifact. |
| “The URL in the POM is the URL Maven contacted.” | A matching mirror may replace it before transport. |
| “Server credentials match the original repository ID after mirroring.” | For the selected mirror, credentials are looked up by the mirror ID. |
| “If my warm local repository works, CI network policy is correct.” | Warm cache can mask remote routing/authentication problems. |
| “settings.xml is safe to commit if it works on my laptop.” | It is user/environment state and may contain credentials or machine-specific routes. |
Knowledge check
A dependency repository in the POM has ID
internal, but settings maps it to mirror ID
corp-mirror. Which server ID should hold
credentials for the actual mirrored connection?
corp-mirror, because the selected mirror's ID is
used to locate its server credentials.
Why is help:active-profiles evidence more useful
than asking “which environment am I on?”
Because it shows the exact Maven profile IDs and their sources that changed the effective build model.
What is the safest first response when a build works from a warm cache but fails on an empty CI worker?
Keep the normal cache intact, reproduce with an isolated local repository, then inspect effective settings/repository routing and the original resolution error.
Where should a portable dependency coordinate live: POM or user settings?
In the POM. Settings should carry environment access policy such as mirrors, proxies, credentials, and user-specific profile inputs.
Why should a CLI -D override be recorded in CI
evidence?
It is an invocation-level user property that can silently change values used by the effective model/plugins even when source files did not change.
12. Summary and bridge
Chapter 08 starts by making the environment boundary explicit: POM and project wrapper/config are repository-owned build intent; settings, proxy/mirror/server credentials, process environment, and caches are controlled execution context. The effective model is the evidence that joins them. Lesson 2 now builds a safe local fixture so each layer can be observed rather than merely described.
Official references and version notes
Version-sensitive statements in this lesson were checked against Apache Maven primary documentation on 2026-08-23. The mandatory path uses Maven 3.9.16 through Maven Wrapper 3.3.4, JDK 21 to run Maven, Java 17 as the project release target, Help Plugin 3.5.2, Dependency Plugin 3.11.0, Compiler Plugin 3.15.0, Resources Plugin 3.5.0, Surefire 3.5.6, and JAR Plugin 3.5.1. Maven 4-only profile syntax and preview behavior are not required here.
- Maven — Settings Reference
- Maven — Introduction to Build Profiles
- Maven — POM Reference / Properties
- Maven — Using Mirrors for Repositories
- Maven — Setting up Multiple Repositories
- Maven — Security and Deployment Settings
- Maven — Injecting POM Properties via settings.xml
- Maven Help Plugin 3.5.2
- Maven Dependency Plugin 3.11.0
- Maven Compiler Plugin 3.15.0
- Maven JAR Plugin 3.5.1
- Maven Resources Plugin 3.5.0
- Maven Surefire 3.5.6
- Apache Maven Wrapper
- Maven 3.9.16 Release Notes
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.