com-lihaoyi/mill: a JVM build tool that replaces pom.xml with build.mill.yaml
A better build tool for Java, Scala and Kotlin: Simpler than Maven, easier than Gradle, with 3-7x faster dev workflows than other JVM build tools
At a glance
- What is it?
- Mill targets Java, Scala and Kotlin teams that find Maven verbose and Gradle hard to reason about. This review covers its YAML and Scala build definitions, the ./mill command line, the MIT licence, and where the tool still expects you to write code.
- Who is it for?
- Adopt Mill if your project is Java, Scala or Kotlin on the JVM and your current build file has grown into something nobody on the team wants to edit. Do not adopt it if your build depends on a plugin ecosystem that only exists for Maven or Gradle, because the repository shows a Mill-specific plugin layout rather than a compatibility layer.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Scala, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Mill replaces, and for whom
The problem Mill addresses is stated plainly in its readme: JVM build tools have a reputation for being sluggish, complicated, and confusing. Maven expresses a build in XML that grows quickly, and Gradle expresses it in a Groovy or Kotlin DSL whose evaluation model many Java developers never fully internalise. Mill's answer is to offer two surfaces instead of one. A declarative build.mill.yaml file covers the common case, and the readme claims such files are often one tenth the line count of an equivalent pom.xml. When the declarative surface runs out, the build moves into Scala code, which the project frames as object-oriented and therefore intuitive for Java developers.
The audience is narrow and specific. The repository topics list android, java, kotlin, scala, scala-js and scala-native, and the example directory contains a folder per target: example/javalib, example/kotlinlib, example/scalalib, example/androidlib, example/groovylib, example/javascriptlib and example/pythonlib. That is a JVM-first tool. A team writing Go or Rust has no reason to look at it, and a team whose build is a single javac invocation has no reason either. Mill is for projects where the build itself has become a component that needs maintaining.
The two build surfaces: build.mill.yaml and Scala build files
The mechanism visible in the readme is a module model. A build file declares that it extends a module type, and that module supplies the tasks. The readme's own example is four lines: it extends JavaModule and lists two Maven coordinates under mvnDeps. From that, the tasks compile, run and test become available without being written. This is the part that differs from Maven in kind rather than degree. In Maven you configure plugins to attach goals to phases. In Mill you extend a module and inherit its task graph, then override the pieces you need.
The repository layout confirms the split. There is a build.mill at the top level, a mill-build directory, and a mill script plus mill.bat at the root, which is the launcher pair for Unix and Windows. The example/extending directory exists specifically for the case where the declarative file is not enough. That directory is the honest signal about where the complexity goes: it does not disappear, it moves into Scala. A Java developer who has never written Scala will read the YAML comfortably and will need to learn something new the first time a custom task is required. The readme presents this as easier than Gradle, and for someone who already knows Java the argument holds, but it is still a second language in the build.
Installing Mill and running a first build
The project distributes through Maven Central under the coordinate com.lihaoyi:mill-dist, and the readme carries a version attribute of 1.1.10 for the stable line, with 1.1.9, 1.1.8 and 1.1.7 appearing in the release list. The repository root contains a mill shell script and a mill.bat for Windows, which is the launcher the documentation points at. The readme does not spell out a bootstrap download command, so the reliable starting point is the documentation site at mill-build.org rather than a guessed installer line.
Once a launcher is present, a minimal build for a Java project is the readme's own example. Create a file named build.mill.yaml in the project root with this content:
extends: JavaModule
mvnDeps:
- org.thymeleaf:thymeleaf:3.1.1.RELEASE
- org.slf4j:slf4j-nop:2.0.7The extends key names the module type, and mvnDeps holds ordinary Maven coordinates. With that file in place, the readme shows three commands. The first compiles sources into classfiles:
./mill compileThe second runs the project, passing a flag through to the application. The readme's example application takes a --text argument and prints an HTML fragment:
./mill run --text helloThe expected output shown in the readme is a single h1 element containing the word hello. The third command runs the test suite:
./mill testThe readme's sample output lists individual test names finishing and then a summary line reading 0 failed, 0 ignored, 2 total. If you see that summary shape, the build is wired correctly. On Windows the same commands go through mill.bat instead of the shell script.
Where Mill gets in the way
The clearest limitation is the one the repository structure admits. Mill's own build is written in Mill: the root build.mill, the mill-build directory and the core, libs, runner, testkit and integration directories are the tool building itself. That is a strong signal of self-hosting, and it is also a warning. Debugging a build that is written in the same language as the build tool means the failure can live in your build file, in a module you extended, or in Mill itself, and the boundary is not always obvious from the error.
The second limitation is ecosystem reach. Maven Central is the dependency source, so library resolution is not a problem. Build plugins are a different matter. Maven and Gradle have accumulated plugins for code coverage gates, release publishing, container image building and static analysis, and Mill does not consume those. The repository topics include mill-plugin, which indicates Mill has its own plugin mechanism rather than a compatibility shim. A team whose build is mostly a chain of third-party plugins is not the audience for this tool, and migrating would mean rewriting that chain.
The third limitation is the launcher. The presence of both mill and mill.bat in the repository root means the entry point is a script that has to be present and executable in the working tree. That is normal for wrapper-style tools, but it does mean CI configuration has to carry the launcher along with the build definition, and the readme does not document a fallback for environments where fetching the launcher is not possible.
Mill against Maven, and against Gradle
The readme makes both comparisons directly and links to dedicated pages for each. Against Maven the argument is line count and declarative clarity: build.mill.yaml files are described as often one tenth the lines of a pom.xml. The difference in approach is real. Maven's model is a fixed lifecycle with plugins bound to phases, so the build's shape is imposed before you write anything. Mill's model is inheritance from a module, so the build's shape comes from what you extend. A four-line file that compiles, runs and tests is not something a pom.xml can express, because the pom has to name the compiler plugin and the surefire plugin before it does anything.
Against Gradle the argument is comprehension rather than size. Gradle's Kotlin and Groovy DSLs are powerful, and Mill's Scala build files are also code, so the two are closer here than the readme's framing suggests. The distinction Mill draws is that its build code is object-oriented and therefore familiar to Java developers. Whether that lands depends on the reader. Someone comfortable with Gradle's task graph will find Mill's module inheritance equally expressive and no simpler. Someone who has only ever written Java will find Mill's mental model closer to what they already know.
The performance claim is stated as 3-7x faster than Maven or Gradle, attributed to aggressive caching and parallelism, with a linked comparison page. That figure comes from the project's own documentation and is not something this review can verify.
Licence, maintenance and the cost of upgrading
Mill is MIT licensed. For a build tool that is about as permissive as it gets: you can use it commercially, modify it, and ship it inside a product without a copyleft obligation. The practical consequence is that embedding the launcher in a corporate image or a CI base layer raises no licensing question. This is not legal advice, and a team with unusual redistribution requirements should read the LICENSE file at the repository root, which is the authoritative text.
On maintenance, the last push to the default branch was on 2026-09-24, four days before this writing, and the most recent release in the list is 1.1.9 from 2026-09-07. Releases 1.1.8 and 1.1.7 landed in the two months before that. The cadence is monthly-ish on the 1.1 line, which is the kind of rhythm that makes pinning a version sensible rather than optional.
The upgrade cost is concentrated in the build files rather than in application code. Mill's own repository carries a changelog.adoc, and the readme links to it as the place where changes are recorded. A team on 1.1.x should read that file before moving, because a change to a module's task signatures will surface as a build error rather than a runtime one, which is the better failure mode. The repository also pins a JVM version through .mill-jvm-version and default-mill-jvm-version at the root, so the toolchain expectation is explicit and can be checked before an upgrade rather than discovered during one.
Editorial conclusion
Adopt Mill if your project is Java, Scala or Kotlin on the JVM and your current build file has grown into something nobody on the team wants to edit. Do not adopt it if your build depends on a plugin ecosystem that only exists for Maven or Gradle, because the repository shows a Mill-specific plugin layout rather than a compatibility layer. Before committing, verify three things: that the mill launcher script or mill.bat runs on your JDK, that your dependency coordinates resolve through mvnDeps, and that the modules you need are covered by the example directories in the repository, since those are the only worked configurations the project ships.
Frequently asked questions
What is the com-lihaoyi Mill build tool?
Mill is a build tool for JVM projects in Java, Scala and Kotlin. Its readme describes it as simpler than Maven, easier than Gradle, and 3-7x faster than other JVM build tools due to caching and parallelism.
How do I install Mill and run a Java project with it?
The repository root ships a mill launcher script and a mill.bat for Windows, and the distribution is published on Maven Central as com.lihaoyi:mill-dist. A minimal project needs a build.mill.yaml extending JavaModule with mvnDeps listed, after which ./mill compile, ./mill run and ./mill test work.
How does Mill compare with Maven for a Java build?
The readme states that declarative build.mill.yaml files are often one tenth the lines of a pom.xml. The structural difference is that Maven binds plugins to a fixed lifecycle, while Mill inherits tasks by extending a module such as JavaModule.
Can Mill use existing Maven dependencies and plugins?
Dependencies come from Maven Central through the mvnDeps key, as in the readme example that pulls org.thymeleaf:thymeleaf:3.1.1.RELEASE. Build plugins are a separate matter: the repository lists mill-plugin among its topics, indicating Mill has its own plugin mechanism rather than consuming Maven or Gradle plugins.
What licence does Mill use?
Mill is MIT licensed, according to the LICENSE file at the repository root. That permits commercial use and modification without a copyleft obligation on your own code.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/com-lihaoyi-mill)