Skip to main content

Package ⚡️

caution

The Package command is restricted and requires setting the --power option to be used. You can pass it explicitly or set it globally by running:

scala-cli config power true

The package command can package your Scala code in various formats, such as:

Default package format

The default package format writes a lightweight launcher JAR, like the "bootstrap" JAR files generated by coursier. These JARs tend to have a small size (mostly containing only the byte code from your own sources), can be generated fast, and download their dependencies upon first launch via coursier.

Such JARs can be copied to other machines, and will run fine there. Their only requirement is that the java command needs to be available in the PATH:

object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package Hello.scala -o hello
./hello
Hello

Library JARs

Library JARs are suitable if you plan to put the resulting JAR in a class path, rather than running it as is. These follow the same format as the JARs of libraries published to Maven Central:

package mylib

class MyLibrary {
def message = "Hello"
}
scala-cli --power package MyLibrary.scala -o my-library.jar --library
javap -cp my-library.jar mylib.MyLibrary
Compiled from "MyLibrary.scala"
public class mylib.MyLibrary {
public java.lang.String message();
public mylib.MyLibrary();
}

Assemblies

Assemblies blend your dependencies and your sources' byte code together in a single JAR file. As a result, assemblies can be run as is, just like bootstraps, but don't need to download anything upon first launch. Because of that, assemblies also tend to be bigger, and somewhat slower to generate:

object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package Hello.scala -o hello --assembly
./hello
Hello

By default assemblies are self-executable, just like the default package format. With the --preamble=false option, you can build an assembly that just contains the JAR and does not contain any built-in Bash code, and therefore can be launched directly with Java and is more portable:

scala-cli --power package Hello.scala -o hello.jar --assembly --preamble=false
java -jar hello.jar
Hello

Docker container

Scala CLI can create an executable application and package it into a docker image.

For example, here’s an application that will be executed in a docker container:

object HelloDocker extends App {
println("Hello from Docker")
}

Passing --docker to the package sub-command generates a docker image. The docker image name parameter --docker-image-repository is mandatory.

The following command generates a hello-docker image with the latest tag:

scala-cli --power package --docker HelloDocker.scala --docker-image-repository hello-docker
docker run hello-docker
Hello from Docker

You can also create Docker images for Scala.js and Scala Native applications. The following command shows how to create a Docker image (--docker) for a Scala.js (--js) application:

scala-cli --power package --js --docker HelloDocker.scala --docker-image-repository hello-docker

Packaging Scala Native applications to a Docker image is only supported on Linux.

The following command shows how to do that:

scala-cli --power package --native --docker HelloDocker.scala --docker-image-repository hello-docker

Building Docker container from base image

--docker-from lets you specify your base docker image.

The following command generate a hello-docker image using base image openjdk:11

scala-cli --power package --docker HelloDocker.scala --docker-from openjdk:11 --docker-image-repository hello-docker

Scala.js

Packaging Scala.js applications results in a .js file, which can be run with node:

object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package --js HelloJs.scala -o hello.js
node hello.js
Hello

Note that Scala CLI doesn't offer the ability to link the resulting JavaScript with linkers, such as Webpack (yet).

Native image

GraalVM native image makes it possible to build native executables out of JVM applications. It can be used from Scala CLI to build native executables for Scala applications.

object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package Hello.scala -o hello --native-image
./hello
Hello

Note that Scala CLI automatically downloads and unpacks a GraalVM distribution using the JVM management capabilities of coursier.

Several options can be passed to adjust the GraalVM version used by Scala CLI:

  • --graalvm-jvm-id accepts a JVM identifier, such as graalvm-java17:22.0.0 or graalvm-java17:21 (short versions accepted).
  • --graalvm-java-version makes it possible to specify only a target Java version, such as 11 or 17 (note that only specific Java versions may be supported by the default GraalVM version that Scala CLI picks)
  • --graalvm-version makes it possible to specify only a GraalVM version, such as 22.0.0 or 21 (short versions accepted)
  • --graalvm-args makes it possible to pass args to GraalVM version

Scala Native

Packaging a Scala Native application results in a native executable:

object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package --native HelloNative.scala -S 2.13 -o hello
file hello
hello: Mach-O 64-bit executable x86_64
./hello
Hello

OS-specific packages

Scala CLI also lets you package Scala code as OS-specific packages. This feature is somewhat experimental, and supports the following formats, provided they're compatible with the operating system you're running Scala CLI on:

object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package --deb Hello.scala -o hello.deb
file hello
hello: Mach-O 64-bit executable x86_64
./hello
Hello

Debian

DEB is the package format for the Debian Linux distribution. To build a Debian package, you will need to have dpkg-deb installed.

Example:

scala-cli --power package --deb --output 'path.deb' Hello.scala

Mandatory arguments

  • version
  • maintainer
  • description
  • output-path

Optional arguments

  • force
  • launcher-app
  • debian-conflicts
  • debian-dependencies
  • architecture

RedHat

RPM is the software package format for RedHat distributions. To build a RedHat Package, you will need to have rpmbuild installed.

Example:

scala-cli --power package --rpm --output 'path.rpm' Hello.scala

Mandatory arguments

  • version
  • description
  • license
  • output-path

Optional arguments

  • force
  • launcher-app
  • release
  • rpm-architecture

macOS (PKG)

PKG is a software package format for macOS. To build a PKG you will need to have pkgbuild installed.

Example:

`scala-cli --power package --pkg --output 'path.pkg` Hello.scala

Mandatory arguments

  • version
  • identifier
  • output-path

Optional arguments

  • force
  • launcher-app

Windows

MSI is a software package format for Windows. To build an MSI installer, you will need to have WIX Toolset installed.

Example:

scala-cli --power package --msi --output path.msi Hello.scala

Mandatory arguments

  • version
  • maintainer
  • licence-path
  • product-name
  • output-path

Optional arguments

  • force
  • launcher-app
  • exit-dialog
  • logo-path

Using directives

Instead of passing the package options directly from bash, it is possible to pass some of them with using directives.

packaging.packageType

This using directive makes it possible to define the type of the package generated by the package command. For example:

//> using packaging.packageType assembly

Available types: assembly, raw-assembly, bootstrap, library, source, doc, spark, js, native, docker, graalvm, deb, dmg, pkg, rpm, msi.

packaging.output

This using directive makes it possible to define the destination path of the package generated by the package command. For example:

//> using packaging.output foo

The using directive above makes it possible to create a package named foo inside the current directory.

packaging.graalvmArgs

This using directive makes it possible to pass args to GraalVM:

//> using packaging.graalvmArgs --no-fallback --enable-url-protocols=http,https

Docker

packaging.dockerFrom

The using directive allows you to define the base Docker image that is used to run your application.

//> using packaging.dockerFrom openjdk:11

packaging.dockerFrom

The using directive allows you to define the generated Docker image tag.

//> using packaging.dockerImageTag 1.0.0

packaging.dockerImageRegistry

The using directive allows you to define the image registry.

//> using packaging.dockerImageRegistry virtuslab

packaging.dockerImageRepository

The using directive allows you to define the image repository.

//> using packaging.dockerImageRepository scala-cli