Java/02core11 min

Maven vs Gradle — building

Every Java project needs a build tool — it manages dependencies, compiles, tests and packages. Two dominate the ecosystem: Maven (declarative, XML) and Gradle (flexible, a Kotlin/Groovy script). This lesson compares them and shows our conventions.

Maven — the declarative standard

Maven describes the project in pom.xml and works according to a fixed lifecycle (validate → compile → test → package → install → deploy). Simple, predictable.

<project>
  <groupId>com.professnet.zeus</groupId>
  <artifactId>inventory-service</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.release>21</maven.compiler.release>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>
</project>
mvn clean verify       # compilation + tests + checks
mvn package            # build the artifact (jar)

Gradle — flexible and fast

Gradle uses a script (we prefer the Kotlin DSL — build.gradle.kts). It is faster thanks to a build cache and incremental builds, but it demands more discipline.

plugins {
    java
    id("org.springframework.boot") version "3.3.0"
}

java {
    toolchain { languageVersion = JavaLanguageVersion.of(21) }
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}
./gradlew build        # compilation + tests
./gradlew bootJar      # Spring Boot artifact

Comparison

FeatureMavenGradle
ConfigurationXML, declarativeKotlin/Groovy, programmable
Learning curvegentlesteep
Speedslowerfaster (cache, incremental)
Flexibilitylimitedvery high
Readability for newcomershighdepends on discipline

ProfessNet standard: for simple, typical services we choose Maven (predictability, a low barrier to entry). For large, multi-module projects and monorepos where build time matters — Gradle with the Kotlin DSL.

Wrapper — a reproducible build

We always commit the wrapper (mvnw / gradlew). It guarantees that everyone builds with the same version of the tool, regardless of what they have on their machine.

./mvnw clean verify        # not 'mvn' — the wrapper from the repo
./gradlew build            # not 'gradle'

ProfessNet standard: in CI and locally we use the wrapper, not a global installation. The tool version is pinned by .mvn/wrapper or gradle/wrapper/gradle-wrapper.properties.

Dependencies — scopes and BOM

We pin the versions of related libraries via a BOM (e.g. Spring Boot dependencies) so we don't manage each version separately.

Scope (Maven / Gradle)Meaning
compile / implementationavailable at compile and runtime
provided / compileOnlycompile only (e.g. Lombok)
test / testImplementationtests only

Tip: don't mix manual versions with a BOM. If the BOM provides a version, don't override it without a reason — that's a source of classpath conflicts.


Maven for simplicity, Gradle for scale — both with a wrapper and consistent dependency management. We decide on the tool once per project and then stick to it consistently.