skip to content

How do plugin goals get associated with lifecycle phases, and how can you bind your own goal to a specific phase?

level: seniorimportance: should knowfreq 55%

answer

  1. phase = slot, goal = work
  2. packaging chooses default bindings
  3. <execution> = phase + goals
  4. same phase = declaration order
  5. mvn plugin:goal runs off-lifecycle

basics

~10 s

Lifecycle phases run plugin goals bound to them. Some bindings are default (chosen by packaging type); you add your own by declaring a plugin <execution> with a <phase> and <goals> in the POM's <build><plugins>.

solid answer

~40 s

A phase does nothing by itself; the work comes from plugin goals bound to it. Maven provides default bindings based on the project's <packaging> (e.g. for jar, compiler:compile binds to compile, surefire:test to test, jar:jar to package). You add custom behavior by declaring a plugin in <build><plugins> with an <execution> that specifies an <id>, a <phase>, and the <goals> to run there. For example, binding the exec-maven-plugin or a code-generation plugin to generate-sources, or failsafe:integration-test to integration-test. Multiple goals can bind to one phase and run in declaration order. You can also run a goal directly off-lifecycle via 'mvn plugin:goal' (e.g. 'mvn dependency:tree'), which executes just that goal without traversing phases. Understanding binding is what lets you extend the build deterministically rather than scripting outside Maven.

code

xml · 15 lines
xml
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>build-helper-maven-plugin</artifactId>
  <version>3.6.0</version>
  <executions>
    <execution>
      <id>add-generated-sources</id>
      <phase>generate-sources</phase>
      <goals><goal>add-source</goal></goals>
      <configuration>
        <sources><source>target/generated</source></sources>
      </configuration>
    </execution>
  </executions>
</plugin>

go deeper

for a junior

Know that goals do the work and packaging gives defaults.

for a middle

Be able to add a plugin execution with phase + goals.

for a senior

Reason about execution ordering, default phases of goals, and off-lifecycle invocation.

for a principal

Design reusable plugin-binding conventions (parent POM / build profiles) and govern plugin versions across the org.

## Phases vs goals A **phase** is just a slot in the lifecycle. A **goal** is a concrete task implemented by a **plugin** (a plugin is a Maven artifact bundling related goals). Goals are referenced as `plugin:goal`, e.g. `compiler:compile`, `surefire:test`, `jar:jar`, `dependency:tree`. Work happens only because goals are **bound** to phases. ## Default (packaging-driven) bindings When you set `<packaging>jar</packaging>`, Maven applies a standard set of bindings, including: - `process-resources` → `resources:resources` - `compile` → `compiler:compile` - `test-compile` → `compiler:testCompile` - `test` → `surefire:test` - `package` → `jar:jar` - `install` → `install:install` - `deploy` → `deploy:deploy` Different packaging (`war`, `pom`, `maven-plugin`) yields different default bindings. ## Adding your own binding Declare a plugin `<execution>` with a `<phase>` and `<goals>`: ```xml <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>3.2.5</version> <executions> <execution> <id>integration-tests</id> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> <!-- phase defaults to the goal's own default; can override --> </execution> </executions> </plugin> </plugins> </build> ``` Some goals declare a **default phase** (Failsafe's `integration-test` goal defaults to the integration-test phase), so you may omit `<phase>`. For arbitrary goals, set `<phase>` explicitly, e.g. bind a code generator to `generate-sources`. ## Multiple goals on one phase More than one goal can bind to the same phase; they execute in the order they appear in the POM. This ordering matters when one step produces input for the next. ## Running a goal directly You can invoke a goal without a lifecycle: `mvn dependency:tree` or `mvn help:effective-pom`. This runs only that goal and skips phase traversal — handy for diagnostics. ## Inspecting effective bindings `mvn help:describe -Dcmd=package` shows what goals are bound to a phase; `mvn help:effective-pom` shows the resolved build configuration.

  • How do you run two goals at the same phase in a guaranteed order?
    Declare both executions in the POM; goals bound to the same phase execute in the order they are declared.
  • How can you see which goals are bound to the package phase?
    Use 'mvn help:describe -Dcmd=package' or inspect 'mvn help:effective-pom'.
  • What's the difference between 'mvn install' and 'mvn install:install'?
    'mvn install' runs the lifecycle through the install phase; 'mvn install:install' runs only the install goal directly, off-lifecycle.

saying these in an interview costs you the question

  • Saying phases run goals magically without bindings
  • Claiming you can only use Maven's built-in goals
  • Ignoring that default bindings depend on packaging type
  • Confusing the phase 'install' with the goal 'install:install'

context