What is the difference between Scala runner and Scala CLI

Author Image

Piotr Chabelski

Scala Engineer @ Scala CLI

40 minutes read

Some of you may have heard that as of SIP-46, Scala CLI is to become the new default runner that will replace the old scala script. Upon receiving this information, many questions arise. Namely, what is Scala CLI and what is it good for? What does this change mean for the Scala community? Or, as many everyday Scala users could probably ask – what even is the scala runner? 

We will try to answer these questions in the following run-through of the situation.

Please note that for the reader’s convenience, we will differentiate the old runner as scala and the new runner (Scala CLI) as scala-cli to give examples in this post, unless otherwise stated. Please also note that the new runner is already available as scala under the scala-experimental installation at the time of writing this post.

What is the scala runner?

Since you are reading this, it is safe to assume you use Scala in some capacity in your life, be it for your job, university, pet project or any other environment. That means you probably also have the language installed on your local machine. 

The average Scala installation gives you access to the following command-line applications:

  • scalac– the app used to interact with the Scala compiler
  • scalap – the Scala class file decoder
  • scaladoc  – the command-line utility for generating Scaladoc
  • scala– the runner we’re discussing in this article

As the name implies, the scala runner is a command-line app that runs Scala code.

Given a simple HelloWorld.scala example:

java

object Hello extends App {
    println("Hello world")
}

Using the runner, you could run the file straight from the command line like this:

bash

scala HelloWorld.scala
# Hello world

Another commonly used feature would be entering the repl:

bash

scala
# Welcome to Scala 3.2.1 (17.0.5, Java OpenJDK 64-Bit Server VM).
# Type in expressions for evaluation. Or try :help.
#
# scala> 

Why do we need a new scala runner?

Until now, the scala runner used to be primarily a power user tool. Its full scope of usefulness was not widely known. Its features have been relatively limited, not offering much beyond launching the repl and running .scala files. To do anything non-basic with Scala, you would immediately have to turn to a build tool, like SBT or Mill. And even when it comes to launching the REPL, most Scala coders have been using it from SBT, skipping the runner altogether. As a result, the utility has gradually been getting less and less attention. It seems like an unused opportunity since we are talking about an app installed along with the compiler on many Scala coders’ machines. 

Scala CLI is meant to be a game changer, being the runner “with batteries included”, targeting not just power users but the whole Scala community.

Scala CLI showcase

Scala CLI is a relatively new open-source command-line tool from VirtusLab, developed since mid-2021. Its core use cases include prototyping, education, scripting, and single-module projects. It allows users to not just run their Scala code from the command line but also compile, package and more.

Scala CLI is not meant to be a replacement for full-fledged build tools (like Mill or SBT), but is perfectly sufficient to act as one for simple projects consisting of a single module.

Beyond the JVM platform, the tool also plays nicely with Scala Native and Scala.js

Its features are divided into sub-commands. Here is a list of some  of the more important ones:

  • run, covers the runner functionality
  • test enables running tests
  • compile, compiles the given inputs
  • package allows the user to create a jar, a native binary, or even a docker image
  • fmt allows the user to format code, running scalafmt under the hood
  • doc, enables the generation of API documentation

More features are planned for the future, with things like publishing, Python, Spark, and Markdown support being in the experimental phase.

There’s also IDE support for IDEA IntelliJ and VS Code with Metals

Advantages Scala CLI has over the old scala runner

Now, that’s all nice and good, but when it comes down to the actual runner functionalities, how is Scala CLI better than its predecessor?

Simpler setup

First, the setup is a lot easier. We mean the language setup and especially the whole development environment. Normally, you would have to separately install the appropriate Java version, scalafmt (a Scala formatter used in a majority of projects) and other things, potentially including a build tool. Scala CLI does all that for the user.

Want to work with a particular Scala version other than the one available by default on your PATH? Nothing simpler. You can change it just by specifying it with an option.

bash

scala-cli -S 2.13
# Welcome to Scala 2.13.10 (OpenJDK 64-Bit Server VM, Java 17.0.5).
# Type in expressions for evaluation. Or try :help.
# 
# scala> 

bash

Similarly, picking a Java version doesn’t require downloading and installing it separately. The tool handles that as well.

In fact, there is no need to install Java separately at all. It’s quite okay to let Scala CLI do it. scalafmt is built in as well, so no need to worry about that.

bash

scala-cli fmt .

Providing a .scalafmt.conf file (configuration for scalafmt) isn’t necessary, either. If it’s not present, Scala CLI will assume default settings.

Separately installing a build tool is also optional unless you’re planning to build a multi-module project. And even then, nothing’s stopping you from using Scala CLI during the prototyping phase and then migrating once the need arises. The export sub-command makes it relatively easy to convert a Scala CLI project to Mill or SBT.

Faster compilation times

Scala CLI uses Bloop under the hood, which makes compilation times a lot faster. 

It’s also one of the easier ways to interact with Bloop. So using Scala CLI’s compile sub-command may be favorable over calling scalac directly if you care about getting something compiled quickly.

Introduction of using directives

Scala CLI introduces the concept of using directives, which allows for defining configuration information in sources. 

This means that things like dependencies or Scala version can be defined straight up in a Scala file without the need for a separate configuration file.

As an example, to define a simple pwd.sc script using Scala 3.2.1 and os-lib 0.9.0, you have to type:

java

//> using scala "3.2.1"
//> using lib "com.lihaoyi::os-lib:0.9.0
println(os.pwd)

bash

scala-cli pwd.sc
# Compiling project (Scala 3.2.1, JVM)
# Compiled project (Scala 3.2.1, JVM)
# ~/scala-cli-tests/demo

This is particularly useful for replicating and reporting bugs, as the exact configuration and code used in a given build can be put in a single code block. Defining dependencies right in the source, where they are immediately used, also speeds up prototyping.

Additionally, using directives can be used in any input accepted by Scala CLI, enabling applying it creatively. For example, nothing stops you from using them in a .java source:

java

//> using jvm "16"
public class Main { 
    public static void main(String[] args) {
        System.out.println(System.getProperty("java.version")); 
    } 
}

bash

scala-cli Main.java
# Compiling project (Java)
# Compiled project (Java)
# 16.0.2

Support for virtual sources

Scala CLI supports virtual sources, which means the input code does not necessarily have to be on your file system.

For example, it’s possible to run a GitHub Gist:

bash

scala-cli https://gist.github.com/Gedochao/9816a2d3ca2597a77dcf8a3d9bc398a2
# Compiling project (Scala 3.2.1, JVM)
# Compiled project (Scala 3.2.1, JVM)
# Hello

Or simply a URL:

bash

scala-cli https://gist.githubusercontent.com/Gedochao/9577c5c7b06cd655b80c5da93a2bf5d3/raw/4600ff9733678c2d36e864384c4cc45188459369/hello.sc
# Compiling project (Scala 3.2.1, JVM)
# Compiled project (Scala 3.2.1, JVM)
# Hello

However, please note that Scala CLI does not provide any sandboxing when writing this article, so make sure you trust any remote sources you decide to run.

There are also other options, like piping sources or process substitution.

IDE support through BSP

Scala CLI has official support for IDEs through BSP (Build Server Protocol), working with IDEA IntelliJ and Metals (with Visual Studio Code or other editors supported by Metals). This allows you to use the runner from the comfort of an IDE’s graphical interface instead of having to use the command line for everything.

vscode-demo

TODO vscode-demo

The new runner’s advanced features

Some of the features delivered by Scala CLI were deemed a bit advanced for the average target user of the scala runner but are nonetheless available behind the --power launcher option. 

A good example of such a power user feature is the package sub-command. It enables packaging code in various formats, like JARs, docker containers, or native images.

For example, the following command packages a project to a GraalVM native image:

bash

scala-cli package Main.scala -o hello --native-image
./hello
# Hello

When installing Scala CLI as scala, you have to pass the --power flag as the first argument to the app (before even a sub-command). 

And so, to achieve the same result with package, producing a GraalVM native image requires the following:

bash

scala --power package Main.scala -o hello --native-image
./hello
# Hello

It’s also possible to enable --power globally, allowing the new runner to always expose all of its features.

bash

scala config power true

Testing the new scala runner early

As mentioned earlier, even though SIP-46 is still in its implementation phase, you can try the new runner early. You can do so by using the scala-experimental installation.

Currently, only two installation methods are supported, with more to come later.

coursier

bash

cs setup
cs install scala-experimental

bash

brew install virtuslab/scala-experimental/scala

Alternatively, you can also install Scala CLI as scala-cli with one of its official installation methods

Try it out and report any issues to the Scala CLI repository!

Liked the article?

Share it with others!

explore more on

Take the first step to a sustained competitive edge for your business

Let's connect

VirtusLab's work has met the mark several times over, and their latest project is no exception. The team is efficient, hard-working, and trustworthy. Customers can expect a proactive team that drives results.

Stephen Rooke
Stephen RookeDirector of Software Development @ Extreme Reach

VirtusLab's engineers are truly Strapi extensions experts. Their knowledge and expertise in the area of Strapi plugins gave us the opportunity to lift our multi-brand CMS implementation to a different level.

facile logo
Leonardo PoddaEngineering Manager @ Facile.it

VirtusLab has been an incredible partner since the early development of Scala 3, essential to a mature and stable Scala 3 ecosystem.

Martin_Odersky
Martin OderskyHead of Programming Research Group @ EPFL

VirtusLab's strength is its knowledge of the latest trends and technologies for creating UIs and its ability to design complex applications. The VirtusLab team's in-depth knowledge, understanding, and experience of MIS systems have been invaluable to us in developing our product. The team is professional and delivers on time – we greatly appreciated this efficiency when working with them.

Michael_Grant
Michael GrantDirector of Development @ Cyber Sec Company