SIP-46 - Scala CLI as default Scala command

IMO the least confusing solution is to de-couple scala-cli from scala. They are separate things with separate versions. An older scala-cli works fine with new Scala releases.

I really don’t think this is too hard to understand for (new) users. I think conflating the version numbers leaks through at some point and leads to deeper confusion than explaining things upfront.

The downside I see is that apt install scala or brew install scala exist today, so we need to deal with those - can packages be deprecated with a message?

Taking a step back, I believe we need to decide what the download page on should recommend. scala-cli is not the only tool that new users need to get, they will at least also need sbt pretty soon after starting.

Do we continue recommending cs? If so, I believe that we should recommend cs setup to install scala-cli. Coursier can be made available across package managers. Having one way to install scala-cli and later another way to get other tools seems like a worse experience, and it’s also a step back from today where cs setup gives everything.


for brew there is at least scala@2 and scala@3 which exist already, then scala would now install the latest scala-cli.

cs setup already installs scala-cli, so instead we can replace the scala command it installs. However I believe cs currently does not support version overrides that mix native launchers (scala cli) and jvm launchers (current scala)

That seems the general consensus now, I am getting a lot of pushback for the idea of aligned releases. Seems we need to do 1.0.0 and try to deal with the issue per package manager.

The downside I see is that apt install scala or brew install scala exist today, so we need to deal with those - can packages be deprecated with a message?

Some of them allow specifying default, so that should help, but we shouldn’t really deprecate the packages, since we want for scala-cli to just replace them.

cs setup will install scala-cli as scala, that’s the plan currently, however we don’t intend to work on also adding coursier across the package managers.

I think what will do now is do 1.0.0 release of ScalaCLI as a first step and then work on updating package managers.

Let us know if anyone disagrees with this plan!


I still think there’s a disconnect. I hear that brew install scala should be the way to “install scala”. But then you get one tool, and for the others you need to do brew install coursier and then cs setup. And then you end up with a second version of scala-cli on your system.

Maybe not everyone wants to use cs setup, and it’s good to have brew install scala-cli and brew install sbt available. I would also support mentioning this on the download page, I assume scala-cli and sbt is all that the majority needs (besides the JVM).

But doing the complicated surgery of replacing the current scala packages to end up with the result above doesn’t seem ideal to me.

But doing the complicated surgery of replacing the current scala packages to end up with the result above doesn’t seem ideal to me.

Isn’t this a separate issue though? We don’t change anything around sbt currently, so the current status quo is maintained.

Maybe we should have some wrapper scripts similar to gradlew, which allow users to quickly run any project, which would mean you would need to only install scala. Or we can also run coursier via scala-cli and install anything that we need, but this is also not ideal.

We’ve discussed it over and over again and there seems to be no ideal scenario. We have a separate package manager for Scala, which shouldn’t be required to use Scala. It’s an amazing tool, but I think forcing it on users creates the disconnect that you are talking about.

I think it could be possible that brew install scala downloads the cs script and runs cs setup, the current cs script works today with e.g. cs setup --yes --apps sbt,scala-experimental --install-dir /usr/local/Cellar/scala/1.0.0/bin - --yes stops it being interactive, and I guess it should find the brew installed JVM, or you can use --env and capture the outputs to modify path how brew expects maybe

If coursier is not the way forward (I personally don’t use it to install tools or JVMs), then we need to come up with a plan for the download page.

I understand I’m bringing in other issues that are not related to scala-cli directly. But also, scala-cli is available today, everyone can use it. What we are discussing now is how to make it the default, the entry point into Scala. This has wider consequences than making the tool available, we need to take the bigger picture into account.

1 Like

I think as the main way of installing Scala we can keep coursier. This is our main package manager and it should install scala-cli as scala when doing setup. We should really think of it as a separate package manager and we have the most control over it.

For any other package manager we just install Scala CLI and let that specific package manager manage updates etc. I don’t believe we 100% need to install sbt everywhere and every time.


I think we can treat scala-cli as GitHub - rust-lang/cargo: The Rust package manager
and for the version, how about:

scala-cli which comes with the same release date of scala3.3.0
scala-cli with bugfix or feature update before scala 3.3.1

and scala-cli will come alone with scala 3.3.1

And a scala-cli can update itself to a newer version

1 Like

There are different ways of installing (I use sdkman on my various ubuntu boxes), but we need a single official way that works on all platforms. Windows is probably the most spread platform on desktop dev machines (among cs beginner students Windows prevail because of gaming until they later transfer to Linux and game less because they code more :slight_smile: ).

Neither brew nor sdkman is good for vanilla Windows so we need something official that work for non WSL-based users, as well as macos (intel+arm), linux (debian-based or not…). As I understand it, cs is the only feasible/available option for that?


For “standard” package manager for Windows you may want to consider Chocolatey. From Wikipedia description:

Chocolatey is a machine-level, command-line package manager and installer for software on Microsoft Windows. It uses the NuGet packaging infrastructure and Windows PowerShell to simplify the process of downloading and installing software.”

I am not associated with Chocolatey, but I do use them to manage software installations on Windows, for instance this the way I install SBT. For me it is an equivalent of brew on Mac and apt on Linux.

1 Like

Yes, so there is a strategic decision to be made if to support all de-facto standard package managers with the costs associated with that. I agree that sdkman, brew, apt, rpm and chocolatey seems a reasonable set to have expectations on to be supported, but it is perhaps even more important to enable a one-click install from the official scala download page on all platforms and coursier provides that with a cross-platform experience, and other package managers are platform specific.

A platform-specific package manager is yet another thing for a beginner to grok and I would like to avoid to have to explain that conditional to all platforms, when a beginner could just do a one-click install if possible. (But it is of course nice that everyone can use their favorite package manager given that there are resources enough to keep all different package up to date in each release cycle…)

1 Like

I would much more prefer if it was just another thing cs managed. That way I don’t need to deal with yet another package manager. Chocolatey might be nice if all your other tools already support it and are installed through it, but if they are not, now you just have more headache as Chocolatey might install things indirectly which you didn’t expect which gets preferred before what you had installed manually.

1 Like

We are currently going with 1.0.0-RC as it’s the safest release number we can use. If some packages updates turn out to be impossible to update we will be able to get back to the earlier ideas as it’s easier to bump to 3.x or more in this case.

As for package managers I feel like cs should still be recommended (with Scala CLI as Scala) as any other solution will differ between OS. However, we should still allow users use different package managers if they want to and as part of that effort we will work on releasing Scala CLI as Scala for any package managers currently supported as seen here Install Scala CLI | Scala CLI

We don’t plan currently to make sbt installed together with Scala CLI via coursier. If needed it would be better to just depend on a separate sbt package and follow standard practises of a specific package manager.


Do you intend to keep shipping the scala-cli command as well, or have it only be scala?

and if so when should the user use one over the other?

We don’t indent to keep scala-cli separate once the roll out is complete. They currently behave in the exact same way so it would be redundant.


SIP-46 - Scala CLI as default Scala command says

We propose to replace current script that is installed as scala with Scala CLI - a batteries included tool to interact with Scala. Scala CLI brings all the features that the commands above provide and expand them with incremental compilation, dependency management, packaging and much more.

This is now an accepted SIP, so if we’re reading the spirit of the SIP, I am guessing the way to go is to fold Scala CLI as scala command as version 3.3.0, implementing sbt-like functionality into the default CLI command with more batteries included.

However, I also agree that it might lead to deeper confusions.

  • If using is not part of the Scala language specification, and basically whatever-Scala-CLI-implements at the time, that can quickly lead to using X works with Scala version 3.4.0, but not 3.2.0, and someone else would say “oh just use Scala 3.4.0 but with Scala version 3.2.0”
  • using doesn’t translate over to other build tools like sbt, Mill, Bazel, Gradle etc, even though it’s now part of “Scala”.
  • using would be different from one machine to another, because depending on the brew means that people could have different CLI installed on the machine? That’s sort of the situation with Bash and Python, but that would be a wrong lesson to learn IMO.
1 Like

Regarding the points of potential confusion:

  • the first point demonstrates really well what’s the downside of using a single name Scala for both the runner and the language; it’d provide a good case for keeping the version of the runner independent (even if the runner is shipped with the Scala package). How quickly could we run into this problem remains to be seen, it’ll likely depend on the development of useful new directives. But any time it happens, it will be too soon, we ideally plan ahead. How about adding a new command which would freeze the script’s requirements into “//> using runner 1.1”? The runner could use it to decide if to run the script.
  • the lack of support of directives in the build tools might not be a big problem as long all documentation makes it very clear that they are only for the runner. The old Scala runner also featured some custom commands that do not exist in Scala (although they are not in the source code). The block-comment prefix should ideally communicate that they are not part of the language.
  • the “works on my machine” problem is indeed likely to occur should the runner be getting some attractive new directives over time. Yet maybe it could be alleviated a bit by the freeze command (I suggested above). The problem might not have a big impact though, provided that the set of directives would remain stable. Then the freeze command might pin the version of the runner to the oldest version which supports given set of directives used.

I think a single warning explaining that this using directive is not available in the current version would suffice in most cases. We just need to explain to the users what they need to do in case of any issues. Any errors we give out need to be “actionable”.

Also, I don’t think we will add any core directives any time soon and anything less prominent might never come up when copying scripts between users.

That’s the thing, a warning might be okay for a non-essential directive but if the script’s correctness would rely on it, then an (actionable) hard-stop error would be much more preferred over trying to run a semi-broken script, which might fail in a complicated way.

I also don’t think that any core directives are coming, but sometimes it’s hard to predict the future.
Right now it seems that the core directive set is stable (like the set of commands available in the old Scala runner), but one can’t tell for sure.