先に要点
- Maven と Gradle は、どちらも Java のビルドと依存ライブラリの管理をする道具です。Maven は XML の pom.xml に決まった型で書き、Gradle は Kotlin か Groovy のスクリプトで手順を組み立てます。
- 書き方や速さの違いはよく語られますが、見落とされやすいのが依存ライブラリの版がぶつかったときの選ばれ方です。Maven 3.9.16 と Gradle 9.7.1 で同じ依存を並べて確かめました。
- 結果は、Maven は宣言の順番を入れ替えるだけで選ばれる版が変わり(3.12.0 と 3.14.0)、Gradle は順番に関係なく高い方(3.14.0)を選びました。どちらも公式ドキュメントに書かれている規則どおりです。
- どちらを使う場合も、大事なライブラリの版は明示して固定するのが確実です。固定の書き方と、実際に効いたことを確かめた出力を載せます。
Java のプロジェクトを始めるとき、あるいは既存のプロジェクトを引き継いだときに、Maven と Gradle のどちらかに出会います。「Maven は XML で古い」「Gradle は速い」といった説明をよく見かけますが、それだけで選ぶと、同じ依存を書いても実際に入るライブラリの版が違うという、もっと実務に響く差を見落とします。
この記事は、Maven と Gradle の違いを、設定ファイル・手順の考え方・速さの仕組みで整理したうえで、依存の版がぶつかったときの挙動を手元で比べた結果をまとめます。ツールの版や必要な Java の版は、2026年9月13日に公式サイトで確認したものです。
ひと目で比べる
| Maven | Gradle | |
|---|---|---|
| 設定ファイル | pom.xml(XML) | build.gradle.kts(Kotlin)または build.gradle(Groovy) |
| 手順の考え方 | 決まったライフサイクルの段階を順に実行する | タスクを組み合わせて手順を作る |
| 変更の無い作業を飛ばす仕組み | ライフサイクルとしては持たない | 変更の無いタスクを飛ばす。ビルドキャッシュも使える(既定では無効) |
| 依存の版がぶつかったとき | 依存の木で近い方。同じ深さなら先に宣言した方 | 高い方 |
| ラッパー | mvnw・mvnw.cmd | gradlew・gradlew.bat |
| 実行に必要な Java | Maven 3.9.16 は Java 8 以上 | Gradle 9 は Java 17〜26 |
| よく使われる場面 | 業務システム、Spring Boot | Android(公式のビルドの仕組み)、Spring Boot |
Spring Boot の公式ドキュメントは、依存管理ができて Maven Central の成果物を使えるビルドツールとして、Maven か Gradle を勧めています。どちらかが公式に推されているわけではありません。Android は Gradle と Android Gradle プラグインでビルドする仕組みになっています。
設定ファイルの違い
同じ2つのライブラリを使う設定を、それぞれで書くとこうなります。
Maven の pom.xml(抜粋):
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.26.0</version>
</dependency>
</dependencies>
Gradle の build.gradle.kts:
plugins {
java
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.apache.commons:commons-text:1.10.0")
implementation("org.apache.commons:commons-compress:1.26.0")
}
Maven は書ける内容が型で決まっているので、誰が書いても似た見た目になります。Gradle はスクリプトなので、条件分岐や独自の処理を書けます。自由度が高い分、書き手によって読みやすさが大きく変わります。
Gradle の Groovy と Kotlin は、拡張子で切り替わります(.gradle と .gradle.kts)。新しくプロジェクトを作る gradle init は、公式ドキュメントによるとほとんどの種類のプロジェクトで Kotlin を既定にしています。
手順の考え方の違い
Maven には決まったライフサイクルがあり、主な段階は validate → compile → test → package → verify → install → deploy の順です。公式ドキュメントのとおり、ある段階を指定すると、その前の段階もすべて実行されます。mvn package と打てば、コンパイルとテストを経て JAR ができます。どのプロジェクトでも同じコマンドで同じことが起きるのが Maven の強みです。
Gradle は、コンパイルやテストなどのタスクを組み合わせて手順を作ります。公式ドキュメントでは、入力が変わっていないタスクを飛ばす仕組み(増分ビルド)に加えて、別のビルドの成果物を再利用するビルドキャッシュが説明されています。ビルドキャッシュは既定では無効で、--build-cache を付けるか、gradle.properties に org.gradle.caching=true を書くと有効になります。「Gradle は速い」と言われる理由の多くはこの仕組みですが、設定しないと使われない部分がある点は押さえておいてください。
依存の版がぶつかったときの違いを試す
ここからが本題です。上の設定では、2つのライブラリがどちらも commons-lang3 に依存していますが、求めている版が違います。commons-text 1.10.0 は 3.12.0、commons-compress 1.26.0 は 3.14.0 です。このとき、実際にどちらの版が使われるかを確かめました。
試した環境は、公式の Docker イメージの Maven 3.9.16(Java 21)と Gradle 9.7.1(Java 21)です。
Maven:宣言の順番で結果が変わる
commons-text を先に書いた pom.xml で、依存の木を表示します。
mvn dependency:tree -Dverbose
example:conflict-demo:jar:1.0
+- org.apache.commons:commons-text:jar:1.10.0:compile
| \- org.apache.commons:commons-lang3:jar:3.12.0:compile
\- org.apache.commons:commons-compress:jar:1.26.0:compile
+- commons-io:commons-io:jar:2.15.1:compile
\- (org.apache.commons:commons-lang3:jar:3.14.0:compile - omitted for conflict with 3.12.0)
3.12.0 が選ばれ、3.14.0 は「ぶつかったので省いた」と表示されました。
次に、pom.xml の2つの依存の順番だけを入れ替えて同じコマンドを実行します。
example:conflict-demo:jar:1.0
+- org.apache.commons:commons-compress:jar:1.26.0:compile
| +- commons-io:commons-io:jar:2.15.1:compile
| \- org.apache.commons:commons-lang3:jar:3.14.0:compile
\- org.apache.commons:commons-text:jar:1.10.0:compile
今度は 3.14.0 が選ばれました。
これは Maven の公式ドキュメントに書かれている規則どおりです。Maven は依存の木でプロジェクトから近い方の版を選び、同じ深さなら先に宣言した方を選びます。今回は2つとも深さが同じなので、書いた順番で決まりました。
Maven では、依存の宣言を並べ替えたり、上の方に1つ追加したりしただけで、その下にぶら下がっていたライブラリの版が変わることがあります。古い版が選ばれると、新しい版で直っていた不具合や脆弱性が戻ってきます。
Gradle:順番に関係なく高い方を選ぶ
同じ2つの依存を、Gradle で並べて表示します。
gradle dependencies --configuration runtimeClasspath
+--- org.apache.commons:commons-text:1.10.0
| \--- org.apache.commons:commons-lang3:3.12.0 -> 3.14.0
\--- org.apache.commons:commons-compress:1.26.0
+--- commons-io:commons-io:2.15.1
\--- org.apache.commons:commons-lang3:3.14.0
commons-text が求めた 3.12.0 に 「-> 3.14.0」と付き、高い方に引き上げられています。なぜその版になったかは、dependencyInsight で確かめられます。
gradle dependencyInsight --dependency commons-lang3 --configuration runtimeClasspath
org.apache.commons:commons-lang3:3.14.0
Variant runtime:
Selection reasons:
- By conflict resolution: between versions 3.14.0 and 3.12.0
Gradle の公式ドキュメントも、既定ではぶつかった版のうち最も高いものを選ぶと説明しています。
高い方が選ばれるのは、脆弱性の修正を取り込みやすいという意味では安心です。一方で、古い版を前提に作られたライブラリが、新しい版で変わった部分に当たって動かなくなる可能性はあります。どちらの規則が安全ということではなく、規則が違うことを知っておくのが大事です。
版を明示して固定する
どちらのツールでも、ぶつかりそうなライブラリは自分で版を決めて書くのが確実です。
Maven:dependencyManagement に書く
pom.xml に次を足し、commons-text を先に書いた(3.12.0 が選ばれていた)状態で試しました。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
</dependencyManagement>
example:conflict-demo:jar:1.0
+- org.apache.commons:commons-text:jar:1.10.0:compile
| \- org.apache.commons:commons-lang3:jar:3.14.0:compile (version managed from 3.12.0)
\- org.apache.commons:commons-compress:jar:1.26.0:compile
+- commons-io:commons-io:jar:2.15.1:compile
\- (org.apache.commons:commons-lang3:jar:3.14.0:compile - version managed from 3.14.0; omitted for duplicate)
「version managed from 3.12.0」と表示され、宣言の順番に関係なく 3.14.0 に揃いました。公式ドキュメントでも、推移的な依存については dependencyManagement の指定が近い方を選ぶ規則より優先されると書かれています。
Gradle:strictly で固定する
Gradle で高い方への引き上げを止めたいときは、版の指定に strictly を使います。わざと低い 3.12.0 に固定して試しました。
implementation("org.apache.commons:commons-lang3") {
version {
strictly("3.12.0")
}
}
+--- org.apache.commons:commons-text:1.10.0
| \--- org.apache.commons:commons-lang3:3.12.0
+--- org.apache.commons:commons-compress:1.26.0
| +--- commons-io:commons-io:2.15.1
| \--- org.apache.commons:commons-lang3:3.14.0 -> 3.12.0
\--- org.apache.commons:commons-lang3:{strictly 3.12.0} -> 3.12.0
commons-compress が求めた 3.14.0 が 3.12.0 に下げられました。固定は効きますが、下げる方向の固定は、上で書いた「古い版で動かなくなる」側の危険を自分で引き受けることになるので、理由をコメントで残してください。
Spring Boot を使っている場合は、Spring Boot 自身が対応済みの依存の版の一覧を持っていて、Maven でも Gradle でも使えます。個別に版を上書きすることもできますが、Spring Framework の版は指定しないよう公式ドキュメントが強く勧めています。
依存の版が意図どおりに上がらない問題は、npm でも形を変えて起きます。npm installは通るのに依存のバージョンが上がらないで、固定の指定が上流の修正を打ち消した例をまとめています。
ラッパーを使う
Maven にも Gradle にも、プロジェクトで決めた版のツールを自動で取ってきて実行するラッパーがあります。
| Maven | Gradle | |
|---|---|---|
| 実行するコマンド | ./mvnw(Windows は mvnw.cmd) | ./gradlew(Windows は gradlew.bat) |
| 版を書く場所 | .mvn/wrapper/maven-wrapper.properties | gradle/wrapper/gradle-wrapper.properties |
| 追加・更新 | mvn wrapper:wrapper | ./gradlew wrapper --gradle-version 9.7.1 |
Gradle の公式ドキュメントは、ラッパーをすべての Gradle ビルドの推奨の実行方法としていて、JAR も含めてラッパーのファイルをバージョン管理に入れるよう書いています。手元のツールの版が人によって違うと、同じ設定でも結果が変わる原因になるので、Maven でもラッパーを使う方が揃えやすくなります。
どちらを選ぶか
- 既存のプロジェクト:今使っている方に合わせます。ツールを替えると、依存の版の選ばれ方まで変わるので、単純な書き換えでは済みません
- Android:Gradle です。Android のビルドの仕組みが Gradle を前提にしています
- Spring Boot の新規プロジェクト:どちらでも公式に使えます。チームが読み慣れている方を選ぶのが現実的です
- 独自の手順が多いビルド:Gradle の方が書きやすくなります。ただし、書き方の約束をチームで決めておかないと読みにくくなります
- 担当者が入れ替わりながら長く保守するシステム:Maven の「決まった型から外れにくい」性質が、そのまま読みやすさになります
どちらを選んでも、ぶつかりやすいライブラリの版は明示する、依存の木を確認するコマンドを知っておく、の2つは共通です。
よくある質問
Maven 4 は使えますか
2026年9月11日時点の Maven 公式のリリース履歴では、Maven 4.0.0 は正式版になっておらず、最新は 4.0.0-rc-6(2026年8月4日)です。実行には Java 17 以上が必要です。正式版として使われているのは Maven 3.9 系です。
Gradle を動かすのに Java 11 では足りませんか
Gradle 9 系は、公式の互換性の表で Java 17〜26 の JVM での実行が必要とされています。筆者の作業用 PC は Java 11 だったため、今回は Docker のイメージで試しました。アプリをコンパイルする Java の版は、ツールチェーンの設定で別に指定できます。
依存の木はどのコマンドで見ればいいですか
Maven は mvn dependency:tree で、ぶつかって省かれた版まで見たいときは -Dverbose を付けます。Gradle は gradle dependencies で全体を、gradle dependencyInsight --dependency 名前 で特定のライブラリがその版になった理由を見られます。
Groovy と Kotlin のどちらで書けばいいですか
新しく作るなら、gradle init の既定になっている Kotlin が無難です。1つのビルドの中で Groovy と Kotlin のスクリプトを混ぜることもできると公式ドキュメントに書かれています。
まとめ
- Maven は決まった型の pom.xml とライフサイクル、Gradle はスクリプトとタスクで手順を作る
- Gradle の速さの仕組みの1つであるビルドキャッシュは、既定では無効
- 依存の版がぶつかると、Maven は近い方(同じ深さなら先に宣言した方)、Gradle は高い方を選ぶ。実際に試すと、Maven は順番を入れ替えるだけで版が変わった
- 大事なライブラリは、Maven なら dependencyManagement、Gradle なら strictly などで版を明示する
- ラッパー(mvnw・gradlew)を使い、ツールの版もプロジェクトで揃える
参考リンク
- Apache Maven:Introduction to the Build Lifecycle
- Apache Maven:Introduction to the Dependency Mechanism(Dependency mediation)
- Apache Maven:Release History
- Apache Maven:Maven Wrapper
- Gradle:Dependency Constraints and Conflict Resolution
- Gradle:Viewing and Debugging Dependencies
- Gradle:Build Cache
- Gradle:Gradle Wrapper
- Gradle:Build Init Plugin
- Gradle:Compatibility Matrix
- Gradle:Releases
- Spring Boot:Build Systems
- Android Developers:Configure your build
- Spring Bootとは?業務システムでよく使われる理由を初心者向けに解説
- npm installは通るのに依存のバージョンが上がらない|overridesが上流の修正を打ち消す