search term:

sbt 2.1.0-RC3

Hi everyone. On behalf of the sbt project, I am happy to announce sbt 2.1.0-RC3. 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:

The full release note is at https://github.com/sbt/sbt/releases/tag/v2.1.0-RC3. See also sbt 2.0 change summary.

How to upgrade

You can upgrade to sbt 2.1.0-RC3 by putting the following in project/build.properties:

sbt.version=2.1.0-RC3

This mechanism allows that sbt 2.1.0-RC3 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-RC3 to upgrade the sbt shell script, sbtn, and the launcher.

Changes since 2.1.0-RC2

Changes with compatibility implications

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

🚀 Other updates

🐛 Bug fixes

100+ bug fixes. See https://github.com/sbt/sbt/releases/tag/v2.1.0-RC3.

Participation

sbt 2.1.0-RC3 was brought to you by 63 contributors and 817 non-merge commits, according to git shortlog -sn --no-merges on sbt (f9763307..v2.1.0-RC3), Zinc (de6a6cef..v2.1.0-M11), and IO (v1.12.1..v1.13.6): Eugene Yokota (@eed3si9n), Kenji Yoshida (@xuwei-k), Jason Zaugg (@retronym), Anatolii Kmetiuk (@anatoliykmetyuk), BrianHotopp, Albert Meltzer (@kitbellew), Lukas Rytz (@lrytz), Jozef Koval (@jozanek), Stas Shevchenko (@stasimus), Dream (@fury0928), Mai Huy Hoàng (@hoangmaihuy), Matthias Kurz (@mkurz), bitloi, BitToby, Daniil Sivak (@seroperson), azdrojowa123, Eugene (@eugkhp), Kasper Kondzielski (@ghostbuster91), Matt Dziuban (@mrdziuban), corevibe555, it-education-md, Ali Rashid (@arashi01), Christian Harrington (@christianharrington), Justin Leider (@jleider), Merlin Hughes (@merlinorg), Michał Pawlik (@majk-p), oolokioo7, PandaMan (@Eruis2579), PhoenixmitX, Renzo (@RenzoMXD), Rikito Taniguchi (@tanishiking), Yannick Heiber (@yhefamly), Alexander (@alexasl), Angel98518, Arnout Engelen (@raboof), atoz96, BinaryWorldTl (@mohamed0803), BitCompass, chrisrock1124, ckstck, Clayton (@claytonlin1110), Clément Pit-Claudel (@cpitclaudel), dev-miro26, Dmitrii Naumenko (@unkarjedy), Fabrizio Colonna (@ColOfAbRiX), fireXtract, Full Stack Developer (@jsdevninja), Idan Ben-Zvi (@idanbenzvi), Ivan Stanislavciuc (@seveneves), jimcody1995, Jonathan Chang (@jonathanchang31), Kevin Lee (@kevin-lee), KilianSwissborg, Li Haoyi (@lihaoyi), Michał Pierściński (@pierscin), Naftoli Gugenheim (@nafg), Philippus Baalman (@Philippus), since-2017-hub, tanaka takaya (@takayahilton), Tu Nguyen (@nguyenyou), Viktor Rudebeck (@vlovgr), volcano303, and Zainab Ali (@zainab-ali). 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).

Scala Center is a non-profit center at EPFL to support education and open source.