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-M9
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-M9
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-M9
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, four scopes (Compile, Test, Runtime, IntegrationTest),
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 somewhere on a wiki.
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 writing a Kotlin task — there is no gradle rename-project.