Research on Mill vs SBT - 2025-04-02
Key Components of Current SBT Infrastructure
1. IWMaterialsVersions
- Simple object with val declarations for all library versions
- Centralized version management through a single file
- Versioning for all major libraries (ZIO, Akka, HTTP clients, etc.)
- Used as a reference in IWMaterialsDeps
2. IWMaterialsDeps
- Contains dependency definitions with proper cross-platform support
- Groups related dependencies with helper methods like
useZIO()
, useZIOAll()
- Handles Scala.js dependencies with
%%%
cross-version support
- Implements specialized library sets (ZIO, Akka, HTTP, etc.)
- Provides standard compiler options for certain libraries (like ZIO JSON)
3. IWScalaProjectPlugin
- Implements an SBT AutoPlugin for standardizing projects
- Sets default Scala version (currently prioritizing Scala 3.6.3)
- Enables SemanticDB for tooling
- Sets up scalafmt and scalafix integration
- Configures publishing to IW Maven repositories
- Sets test logging preferences
4. IWPluginPresets
- Centralizes SBT plugin management
- Provides helper methods for adding common plugin sets
- Handles complex plugin dependencies (like Scala.js ecosystem)
5. VitePlugin
- Example of custom SBT plugin for JavaScript tooling
- Shows integration with external tools like Vite
- Manages dev server lifecycle
- Configures environment variables and file monitoring
Based on our research from the Mill documentation, here are the key aspects of Mill:
1. Core Features
- Supports multiple languages (Java, Scala, Kotlin)
- Faster builds through aggressive caching and parallelism
- Better IDE support with superior autocomplete and navigation
- Requires fewer plugins for common workflows
- Build files are regular Scala code (build.sc)
2. Module System
3. Dependency Management
- Uses Ivy syntax:
ivy"org::name:version"
(with :: for Scala deps)
- Dependencies defined in module definition:
def ivyDeps = Agg(...)
for external dependencies
def moduleDeps = Seq(...)
for internal module dependencies
- Can define custom resolvers and credentials
4. Publishing
- Uses
PublishModule
trait
- Requires
def publishVersion
and def pomSettings
- Example:
object foo extends ScalaModule with PublishModule {
def publishVersion = "0.0.1"
def pomSettings = PomSettings(
description = "Hello",
organization = "com.lihaoyi",
url = "https://github.com/lihaoyi/example",
licenses = Seq(License.MIT)
)
}
5. Extension Development
- Mill uses traits for sharing functionality between modules
- Can create custom modules that extend existing Mill modules
- Extensions are regular JVM libraries that can be published to Maven repos
- Isolated classloaders for worker modules to avoid conflicts
Differences Between SBT and Mill
1. Configuration Syntax
- SBT: DSL in build.sbt files with key-value pairs
- Mill: Regular Scala code in build.sc files, with modules as objects
2. Plugin System
- SBT: Formal plugin system with AutoPlugin
- Mill: Traits and regular libraries, no formal plugin system
3. Dependency Notation
- SBT:
"org" %% "name" % "version"
- Mill:
ivy"org::name:version"
4. Cross Building
- SBT: Uses
+
prefix for commands, crossScalaVersions setting
- Mill: Uses
Cross[Module]
for multi-version builds, with version-specific source dirs
5. Task Definition
- SBT: Tasks defined as settings with complex DSL
- Mill: Tasks defined as methods with explicit dependencies
Mill Equivalent Components Design
1. IWMillVersions
2. IWMillDeps
3. IWScalaModule trait
4. IWPublishModule trait
Implementation Planning
For each component we'll need to:
- Create the basic structure of the Mill support library
- Implement the version and dependency objects
- Create traits for standard module configuration
- Implement publishing support
- Create example modules and migration guides
Mill's trait-based approach should make our implementation more natural and flexible than SBT plugins, as we can create composable traits that work directly with Mill's module system.