Same project, four build tools
A single application. One application's worth of dependencies. One main class.
Here it is, expressed in bleep.yaml, pom.xml, build.sbt, and
build.gradle.kts.
Line counts aren't the point, you'll see sbt's three files come in shorter than bleep's one. The point is the kind of artifact each one is: plain data versus XML versus a DSL with hidden state versus a Kotlin program that mutates a build graph. Read each one with that question in mind.
bleep.yaml, plain data
Same shape across all three languages. The only thing that changes between
tabs is the per-language fields (scala:, kotlin:, dep coordinates) and
the test framework. Each snippet is a real workspace from bleep's own
integration tests; the bleep build server compiles and runs each one on
every commit.
- Kotlin
- Java
- Scala
$schema: https://raw.githubusercontent.com/oyvindberg/bleep/master/schema.json
$version: 1.0.0-M10
jvm:
name: graalvm-community:25.0.1
projects:
myapp:
extends: template-common
platform:
mainClass: com.example.MainKt
myapp-test:
dependencies:
- io.kotest:kotest-runner-junit5-jvm:5.8.0
- org.junit.jupiter:junit-jupiter:5.10.1
dependsOn: myapp
extends: template-common
isTestProject: true
templates:
template-common:
kotlin:
jvmTarget: '25'
version: 2.3.0
platform:
name: jvm
$schema: https://raw.githubusercontent.com/oyvindberg/bleep/master/schema.json
$version: 1.0.0-M10
jvm:
name: graalvm-community:25.0.1
projects:
myapp:
extends: template-common
platform:
mainClass: com.example.Main
myapp-test:
dependencies: org.junit.jupiter:junit-jupiter:5.10.1
dependsOn: myapp
extends: template-common
isTestProject: true
templates:
template-common:
platform:
name: jvm
$schema: https://raw.githubusercontent.com/oyvindberg/bleep/master/schema.json
$version: 1.0.0-M10
jvm:
name: graalvm-community:25.0.1
projects:
myapp:
extends: template-common
platform:
mainClass: com.example.helloMain
myapp-test:
dependencies: org.scalameta::munit:1.0.0
dependsOn: myapp
extends: template-common
isTestProject: true
templates:
template-common:
platform:
name: jvm
scala:
options: -encoding utf8 -feature -unchecked
strict: true
version: 3.8.3
For the per-feature breakdown of each comparison, see the dedicated pages: vs Maven, vs Gradle, vs sbt, vs Mill.
pom.xml. XML
The Kotlin variant. Java and Scala flavors of pom.xml differ only in the
plugin section and dep coordinates, same XML.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myapp</artifactId>
<version>0.1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.version>2.3.0</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>io.kotest</groupId>
<artifactId>kotest-runner-junit5-jvm</artifactId>
<version>5.8.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
</plugin>
</plugins>
</build>
</project>
It is 2026. We are still typing closing tags by hand. There is no need.
build.sbt + project/, a DSL across three files
The Scala variant. Sbt is rarely used outside Scala, the Java/Kotlin flavors exist but nobody actually picks sbt for them.
build.sbt:
ThisBuild / scalaVersion := "3.8.3"
ThisBuild / organization := "com.example"
lazy val myapp = (project in file("."))
.enablePlugins(JavaAppPackaging)
.settings(
name := "myapp",
libraryDependencies ++= Seq(
"com.lihaoyi" %% "fansi" % "0.5.0"
),
Compile / mainClass := Some("com.example.Main")
)
project/build.properties:
sbt.version=1.10.0
project/plugins.sbt:
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.10.0")
Three files, three default configurations (Compile, Test, Runtime)
plus user-defined ones, and a DSL whose every keyword is a global side
effect on a hidden settings graph. sbt-native-packager is enabled
by name; what it does to your build is documented separately on the
plugin's own site.
build.gradle.kts, a Kotlin program
The Kotlin variant. Gradle's Java DSL is similar shape; the Scala flavor exists but isn't widely used.
plugins {
application
kotlin("jvm") version "2.3.0"
}
group = "com.example"
version = "0.1.0-SNAPSHOT"
repositories { mavenCentral() }
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
testImplementation("io.kotest:kotest-runner-junit5-jvm:5.8.0")
}
application {
mainClass.set("com.example.MainKt")
}
tasks.withType<JavaCompile> {
sourceCompatibility = "21"
targetCompatibility = "21"
}
A real Kotlin program that side-effects the build graph. Plus
settings.gradle.kts, gradle.properties, and the wrapper. Renaming
the project means editing rootProject.name in settings.gradle.kts
plus a directory rename; there's no gradle rename-project.