DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Test Automation: Maven Profiles and Parallelization in Azure Pipelines Using IaaS
  • Fast Deployments of Microservices Using Ansible and Kubernetes
  • How to Publish Artifacts to Maven Central
  • CI/CD Using Maven With Connected Applications in Anypoint Platform for Runtime Fabric

Trending

  • SaaS in an Enterprise - An Implementation Roadmap
  • After 9 Years, Microsoft Fulfills This Windows Feature Request
  • Apple and Anthropic Partner on AI-Powered Vibe-Coding Tool – Public Release TBD
  • Simplifying Multi-LLM Integration With KubeMQ
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. Maven Profile Best Practices

Maven Profile Best Practices

By 
Andrew Spencer user avatar
Andrew Spencer
·
Nov. 27, 10 · Interview
Likes (4)
Comment
Save
Tweet
Share
140.2K Views

Join the DZone community and get the full member experience.

Join For Free

Maven profiles, like chainsaws, are a valuable tool, with whose power you can easily get carried away, wielding them upon problems to which they are unsuited. Whilst you're unlikely to sever a leg misusing Maven profiles, I thought it worthwhile to share some suggestions about when and when not to use them. These three best practices are all born from real-world mishaps:

  • The build must pass when no profile has been activated
  • Never use <activeByDefault>
  • Use profiles to manage build-time variables, not run-time variables and not (with rare exceptions) alternative versions of your artifact

I'll expand upon these recommendations in a moment. First, though, let's have a brief round-up of what Maven profiles are and do.

Maven Profiles 101

A Maven profile is a sub-set of POM declarations that you can activate or disactivate according to some condition. When activated, they override the definitions in the corresponding standard tags of the POM. One way to activate a profile is to simply launch Maven with a -P flag followed by the desired profile name(s), but they can also be activated automatically according to a range of contextual conditions: JDK version, OS name and version, presence or absence of a specific file or property. The standard example is when you want certain declarations to take effect automatically under Windows and others under Linux. Almost all the tags that can be placed directly in a POM can also be enclosed within a <profile> tag.

The easiest place to read up further about the basics is the Build Profiles chapter of Sonatype's Maven book. It's freely available, readable, and explains the motivation behind profiles: making the build portable across different environments.

The build must pass when no profile has been activated

(Thanks to for this observation.)

Why?

Good practice is to minimise the effort required to make a successful build. This isn't hard to achieve with Maven, and there's no excuse for a simple mvn clean package not to work. A maintainer coming to the project will not immediately know that profile wibblewibble has to be activated for the build to succeed. Don't make her waste time finding it out.

How to achieve it

It can be achieved simply by providing sensible defaults in the main POM sections, which will be overridden if a profile is activated.

Never use <activeByDefault>

Why not?

This flag activates the profile if no other profile is activated. Consequently, it will fail to activate the profile if any other profile is activated. This seems like a simple rule which would be hard to misunderstand, but in fact it's surprisingly easy to be fooled by its behaviour. When you run a multimodule build, the activeByDefault flag will fail to operate when any profile is activated, even if the profile is not defined in the module where the activeByDefault flag occurs.

(So if you've got a default profile in your persistence module, and a skinny war profile in your web module... when you build the whole project, activating the skinny war profile because you don't want JARs duplicated between WAR and EAR, you'll find your persistence layer is missing something.)

activeByDefault automates profile activation, which is a good thing; activates implicitly, which is less good; and has unexpected behaviour, which is thoroughly bad. By all means activate your profiles automatically, but do it explicitly and automatically, with a clearly defined rule.

How to avoid it

There's another, less documented way to achieve what <activeByDefault> aims to achieve. You can activate a profile in the absence of some property:

<profile id="nofoobar">    <activation>        <property>            <name>!foo.bar</name>        </property>    </activation></profile>

This will activate the profile "nofoobar" whenever the property foo.bar is not defined.

Define that same property in some other profile: nofoobar will automatically become active whenever the other is not. This is admittedly more verbose than <activeByDefault>, but it's more powerful and, most importantly, surprise-free.

Use profiles to adapt to build-time context, not run-time context, and not (with rare exceptions) to produce alternative versions of your artifact

Profiles, in a nutshell, allow you to have multiple builds with a single POM. You can use this ability in two ways:

  • Adapt the build to variable circumstances (developer's machine or CI server; with or without integration tests) whilst still producing the same final artifact, or
  • Produce variant artifacts.

We can further divide the second option into: structural variants, where the executable code in the variants is different, and variants which vary only in the value taken by some variable (such as a database connection parameter).

If you need to vary the value of some variable at run-time, profiles are typically not the best way to achieve this. Producing structural variants is a rarer requirement -- it can happen if you need to target multiple platforms, such as JDK 1.4 and JDK 1.5 -- but it, too, is not recommended by the Maven people, and profiles are not the best way of achieving it.

The most common case where profiles seem like a good solution is when you need different database connection parameters for development, test and production environments. It is tempting to meet this requirement by combining profiles with Maven's resource filtering capability to set variables in the deliverable artifact's configuration files (e.g. Spring context). This is a bad idea.

Why?

  • It's indirect: the point at which a variable's value is determined is far upstream from the point at which it takes effect. It makes work for the software's maintainers, who will need to retrace the chain of events in reverse
  • It's error prone: when there are multiple variants of the same artifact floating around, it's easy to generate or use the wrong one by accident.
  • You can only generate one of the variants per build, since the profiles are mutually exclusive. Therefore you will not be able to use the Maven release plugin if you need release versions of each variant (which you typically will).
  • It's against Maven convention, which is to produce a single artifact per project (plus secondary artifacts such as documentation).
  • It slows down feedback: changing the variable's value requires a rebuild. If you configured at run-time you would only need to restart the application (and perhaps not even that). One should always aim for rapid feedback.

 

Profiles are there to help you ensure your project will build in a variety of environments: a Windows developer's machine and a CI server, for instance. They weren't intended to help you build variant artifacts from the same project, nor to inject run-time configuration into your project.

 

How to achieve it

If you need to get variable runtime configuration into your project, there are alternatives:

  • Use JNDI for your database connections. Your project only contains the resource name of the datasource, which never changes. You configure the appropriate database parameters in the JNDI resource on the server.
  • Use system properties: Spring, for example, will pick these up when attempting to resolve variables in its configuration.
  • Define a standard mechanism for reading values from a configuration file that resides outside the project. For example, you could specify the path to a properties file in a system property.

Structural variants are harder to achieve, and I confess I have no first-hand experience with them. I recommend you read this explanation of how to do them and why they're a bad idea, and if you still want to do them, take the option of multiple JAR plugin or assembly plugin executions, rather than profiles. At least that way, you'll be able to use the release plugin to generate all your artifacts in one build, rather than a single one at a time.

Further reading

  • Profiles chapter from the Sonatype Maven book.
  • Deploying to multiple environments (prod, test, dev):
    • Stackoverflow.com discussion; see the first and top-rated answer. Short of creating a specific project for the run-time configuration, you could simply use run-time parameters such as system properties.
  • Creating multiple artifacts from one project:
    • How to Create Two JARs from One Project (…and why you shouldn’t) by Tim O'Brien of Sonatype (the Maven people)
    • Blog post explaining the same technique
  • Maven best practices (not specifically about profiles):
    • http://mindthegab.com/2010/10/21/boost-your-maven-build-with-best-practices/
    • http://blog.tallan.com/2010/09/16/maven-best-practices/

This article is a completely reworked version of a post from my blog.

Profile (engineering) Apache Maven Continuous Integration/Deployment

Opinions expressed by DZone contributors are their own.

Related

  • Test Automation: Maven Profiles and Parallelization in Azure Pipelines Using IaaS
  • Fast Deployments of Microservices Using Ansible and Kubernetes
  • How to Publish Artifacts to Maven Central
  • CI/CD Using Maven With Connected Applications in Anypoint Platform for Runtime Fabric

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!