sbt 2.1.0-RC2
Hi everyone. On behalf of the sbt project, I am happy to announce sbt 2.1.0-RC2. This is the beta version of the first feature release of sbt 2.x, a binary compatible release focusing on new features.
The headline features of sbt 2.1.0 are:
- Scala 3.9.0 on metabuild
- Ivyless publishing
- Updated
cleantask - Testing UX improvements
- HTTP Bazel cache
- Various performance improvements
The full release note is at https://github.com/sbt/sbt/releases/tag/v2.1.0-RC2. See also sbt 2.0 change summary.
How to upgrade
You can upgrade to sbt 2.1.0-RC2 by putting the following in project/build.properties:
sbt.version=2.1.0-RC2
This mechanism allows that sbt 2.1.0-RC2 is used only for the builds that you want.
Download the official sbt runner from SDKMAN, or download from https://github.com/sbt/sbt/releases/tag/v2.1.0-RC2 to upgrade the sbt shell script, sbtn, and the launcher.
Changes with compatibility implications
- Metabuild is updated to Scala 3.9.
- Apache Ivy is removed from the dependency.
sbtrunner script honorsJAVA_HOME.
Scala 3.9 on metabuild
sbt 2.1.0 updates the Scala version used by the metabuild to Scala 3.9.0.
Since both sbt 2.x and Scala 3.x are only backward compatible across minor versions, appropriate Scala version must be used for building sbt plugins. This also means that a plugin built using sbt 2.1.x will not work on sbt 2.0.x:
| sbt 2.x | Scala 3.x | Plugin works on sbt 2.0.x |
|---|---|---|
| 2.0.x | 3.8.x | ✅ |
| 2.1.0 | 3.9.x | ❌ |
Plugin authors: Here’s how to set the minimal sbt version for your plugin:
pluginCrossBuild / sbtVersion := {
scalaBinaryVersion.value match {
case "2.12" => "1.9.9"
case _ => "2.0.8"
}
}
Publishing
sbt 2.1.0 removes Apache Ivy from its transitive dependency, which was previously used for publishing, and implements Ivyless publishing.
This was contributed by @bitloi, @fury0928, @BrianHotopp, and @eed3si9n in #8686, #8866, #8894, #8975, #8988, #8996, #9069, #9463, #9533, and #9615 etc.
clean task
To restore the semantics of clean in the presence of disk cache, sbt 2.1.0 updates the clean task to act as a cache invalidator. Regardless of the cache state, running clean would invalidate the cache for the next command execution. This can be scoped to subproject or configuration:
$ sbt foo/clean
$ sbt foo/compile
This was contributed by @eed3si9n in #9752.
Test UX improvements
Test summary
When tests are executed, sbt 2.1.0 displays a test summary at the end, listing the failed test suites as follows:
[error] Test summary (2 test tasks failed):
[error] a / Test / testQuick
[error] com.example.a.TestA FAIL
[error] b / Test / testQuick
[error] com.example.b.TestB FAIL
[error]
[error] failed: total 4, failed 2, errors 0, passed 2, cached 2
Successful tests will display only a terse summary by default:
[info] passed: total 4, failed 0, errors 0, passed 4, cached 4
--test_summary=success can override the behavior to list the successful test as well. Test summary was contributed by @eed3si9n and @BrianHotopp in #9602 + #9214.
Test cache opt-out
sbt 2.1.0 can let you opt out of test result caching:
$ sbt test --cache_test_result=false
This was contributed by @anatoliykmetyuk in #9675.
workerMaxInstances and testTopology
sbt 2.1.0 adds new settings workerMaxInstances and testTopology to control test scheduling,
especially of the forked tests. Use Global / workerMaxInstances to change the number of worker instances. The default is set to 2:
// or sbt -Dsbt.worker_max_instances=2
Global / workerMaxInstances := 2
Use the testTopology setting to control whether you want to split the test classes into multiple workers or keep them together. The default was changed to split to 2 groups:
Test / testTopology := TestTopology.subprojectSplit(2)
To keep all classes in a subproject on one worker instead, use:
Test / testTopology := TestTopology.subprojectExclusive
This was contributed by @eed3si9n in #9665.
Source dependency update
sbt 2.1.0 provides better control to handle source dependencies.
This was contributed by @seroperson in #8880.
Identity map optimization
In sbt 2.1.0, a key assignment (:=) whose right-hand side is expr.value short-circuits to x.set(expr).
This is helpful in avoiding JsonFormat[A] when expr is an uncached task.
This was contributed by @eed3si9n in #9831
Task-level caching opt-out
// opt out of compilation cache
Compile / compile / cacheStores := Nil
Test / compile / cacheStores := Nil
// opt out of test cache
Test / test / cacheStores := Nil
This was contributed by @eed3si9n in #9874
Input-only cache
sbt 2.1.0 introduces a new cache level CacheLevelTag.InputOnly:
@cacheLevel(include = Array(CacheLevelTag.InputOnly))
val scalacOptions = taskKey[Seq[String]]("Options for the Scala compiler.")
Similar to Def.uncached(...), scalacOptions will evaluate each time, but scalacOptions.value will participate as an input to other cached task.
This was contributed by @eed3si9n in #9953
HTTP Bazel cache
sbt 2.1.0 adds support for HTTP Bazel cache, in addition to gPRC.
Global / remoteCache := Some(uri("http://127.0.0.1:8000"))
This was contributed by @eed3si9n in #9880
⚡ Performance improvements
- perf: lightweight
UpdateReportcache persistence by @bitloi in #8815 - perf: Cache
AutoPluginprojectSettings/projectConfigurationsby @volcano303 in #9077 - perf: Resolve dependencies in parallel under the super shell by @BrianHotopp in #9295
- Optimize
InterfaceUtilby @xuwei-k in #9223 - perf: Intern
UpdateReportvalues by @hoangmaihuy in #9523 - perf: Keep the Analysis cached across an action cache output sync by @hoangmaihuy in #9550
- perf: Skip extracting a dirzip whose digest already matches by @hoangmaihuy in #9555
- perf: Optimize
UpdateReportdisk format by @hoangmaihuy in #9515 - perf: Skip re-packaging the class directory when zinc recompiles nothing by @hoangmaihuy in #9609
- perf: Copy instead of symlink when restoring the disk cache on APFS by @hoangmaihuy in #9623
- perf: Avoid re-sorting watch inputs on every file event by @stasimus in #9650
- perf: Write
packageBinJARs and action cache zips in parallel by @hoangmaihuy in #9661 - perf: Cut redundant hashing in disk action cache by @stasimus in #9649
- perf: Populate the in-memory cache on a read by @hoangmaihuy in #9657
- perf: Avoid allocating pre/post-condition thunks in
Executeby @retronym in #9885
🚀 Other updates
- Adds project id to Zinc debug log by @Achieve3318 in #8750
- feat: Support
doc / skip := trueby @fury0928 in #8824 - feat: case-insensitive tab completion by @bitloi in #8827
- dependencyTree: add
--appendfor file output in multi-module builds by @oolokioo7 in #8878 - feat: Eviction error for downgrade of Scala 3.x by @bitloi in #8912
- feat: Add English aliases
crossandswitchfor+/++by @jonathanchang31 in #9051 - feat: BSP
buildTarget/dependencyModulesby @jsdevninja in #9085 - feat: Forward test events to listeners as they are emitted by @claytonlin1110 in #9087
- feat: Adds
ModuleID#excludethat acceptsa %% bby @seroperson in #8756 - Specific error message for defining types in
build.sbtby @xuwei-k in #9579 - Use JDK’s Unix domain socket for bootserver by @eed3si9n in #9427
- feat: Adds
Seq[Initialize[Task[T]]]#joinextension method by @jozanek in #9347 - feat: Adds
LoggerContext.removeAppenderfor single appender removal by @stasimus in #9740 - feat: Improve Zinc invalidation debug logs by @jozanek in zinc#1765
- feat: Adds
ProjectMatrix#configureRowsandconfigurePlatformsmethods by @kitbellew in #9765 - feat: Persistent worker for tests by @eed3si9n in #9678
remoteCacheRequestTimeoutsetting by @eed3si9n in #9829- Use JDK 17 UNIX domain socket by @eed3si9n in #9846
CrossVersion: make parser public by @kitbellew in #9864- feat: Support platform in
sbt queryby @eed3si9n in #9876 - feat: Adds
Terminal.withRawInputfor reading single keys by @mkurz in #9948 - feat: Adds
originto the execution log by @eed3si9n in #9944 - feat: Adds
sbt/execsto list running and waiting commands by @eed3si9n in #9984 - feat: Adds
sbt/shutdownrequest with a force option by @azdrojowa123 in #9952 - feat: Adds
sbt/execsChangednotification by @eed3si9n in #10001
🐛 Bug fixes
100+ bug fixes. See https://github.com/sbt/sbt/releases/tag/v2.1.0-RC2.
Participation
sbt 2.1.0-RC2 was brought to you by 49 contributors, according to git shortlog -sn --no-merges on sbt (v2.0.x branch point..v2.1.0-RC2, excluding contributions already released in sbt 2.0.x), Zinc (v2.0.4..v2.1.0-M9), IO (v1.12.2..v1.13.6), and IPC Socket (v1.8.0..v1.8.1): Eugene Yokota (@eed3si9n), Kenji Yoshida (@xuwei-k), Jason Zaugg (@retronym), Anatolii Kmetiuk (@anatoliykmetyuk), @BrianHotopp, Lukas Rytz (@lrytz), Albert Meltzer (@kitbellew), Jozef Koval (@jozanek), Stas Shevchenko (@stasimus), Dream (@fury0928), Mai Huy Hoàng (@hoangmaihuy), @bitloi, Matthias Kurz (@mkurz), @bittoby, Daniil Sivak (@seroperson), Eugene (@eugkhp), Matt Dziuban (@mrdziuban), @azdrojowa123, @corevibe555, Dmitrii Naumenko (@unkarjedy), @it-education-md, @oolokioo7, Christian Harrington (@christianharrington), Ivan Stanislavciuc (@seveneves), Justin Leider (@jleider), Kasper Kondzielski (@ghostbuster91), Merlin Hughes (@merlinorg), @Eruis2579, @PhoenixmitX, Alexander (@alexasl), @Achieve3318, Arnout Engelen (@raboof), @atoz96, @mohamed0803, @bitcompass, @ckstck, Clayton (@claytonlin1110), Clément Pit-Claudel (@cpitclaudel), @jsdevninja, @jimcody1995, Jonathan Chang (@jonathanchang31), Li Haoyi (@lihaoyi), Michał Pierściński (@pierscin), Naftoli Gugenheim (@nafg), Philippus Baalman (@Philippus), @since-2017-hub, Tu Nguyen (@nguyenyou), Viktor Rudebeck (@vlovgr), and @volcano303. Thank you!
Thanks to everyone who’s helped improve sbt and Zinc by using them, reporting bugs, improving our documentation, porting builds, porting plugins, and submitting and reviewing pull requests.
For anyone interested in helping sbt, there are many avenues for you to help, depending on your interest. If you’re interested, Contributing, “help wanted”, “good first issue”, and Discussions are good starting points.
FYI - Scala Days talk
I gave a talk in Scala Days 2026 in Berlin about sbt 2.0 (recording, slide deck).
Donate to Scala Center
Scala Center is a non-profit center at EPFL to support education and open source.