Skip to main content

Offline mode ⚡️

caution

Offline mode is an experimental feature.

Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team on GitHub.

The offline mode for Scala CLI was introduced to be used in two situations:

  • you want to have more control over the artifacts being downloaded
  • your development environment has restricted access to the Internet or certain web domains

In this mode Scala CLI will only use local artifacts cached by coursier. Any attempts to download artifacts will fail unless they're available locally in cache or there is a known fallback. This applies to everything that Scala CLI normally manages behind the scenes:

  • Scala language and compiler artifacts
  • JVM artifacts
  • Bloop artifacts
  • dependency artifacts

How to use the offline mode

To enable offline mode pass the --offline flag to Scala CLI, e.g.:

scala-cli run Main.scala --offline

It is also possible to use the COURSIER_MODE environment variable or coursier.mode java property.

export COURSIER_MODE=offline

or

scala-cli -Dcoursier.mode=offline run Main.scala 

Changes in behaviour

Scala artifacts

In offline mode Scala CLI will not perform any validation of the Scala version specified in the project, it will not be checked if such a version has been released.

JVM artifacts

System JVM will be used or it will be fetched from local cache. If a different JVM version than the system one is required, it is best to export it to the JAVA_HOME environment variable. It is important to know, that currently if a version is specified with --jvm or using jvm Scala CLI will ignore the system JVM and try to fetch via coursier.

To start the Bloop server a JVM with version above 17 is required, if it can't be found compilation will fall back to using scalac instead.

Bloop artifacts

If no artifacts for Bloop are available compilation falls back to using scalac instead.

Dependency artifacts

Any attempt to download a dependency will fail, so it is required to have all the dependencies cached locally before compiling.

Dependencies that reside in local repositories like ~/.ivy2/local will be resolved as usual.

Setting up the environment

The easiest way to set up the environment is to use Coursier.

Installing scala artifacts:

cs install scala:3.3.0 scalac:3.3.0

Installing a JVM:

cs java --jvm 17

Using the two commands above is already enough for running and compiling code using scalac. For fetching code dependencies run:

cs fetch com.lihaoyi::os-lib::0.9.1

Note that the dependency format is the same as for --dep and using dep. More information about it here.

If you want to use Bloop, you can get it with:

cs fetch io.github.alexarchambault.bleep:bloop-frontend_2.12:1.5.11-sc-3 

Note that Scala CLI uses a custom fork of Bloop, so simple cs install bloop won't work.

Setting up the environment manually

It is possible to copy the Scala language artifacts and dependencies to the local Coursier's cache manually. This can be done by creating a directory structure like this:

COURSIER_CACHE_PATH
└── https
└── repo1.maven.org
└── maven2
└── org
└── scala-lang
└── scala-compiler
└── 2.13.12
├── scala-compiler-2.13.12-sources.jar (OPTIONAL)
├── scala-compiler-2.13.12.jar
└── scala-compiler-2.13.12.pom

Path on MacOs ~/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.12

Same for a library:

COURSIER_CACHE_PATH
└── https
└── repo1.maven.org
└── maven2
└── com
└── lihaoyi
└── os-lib_3
└── 0.9.1
├── os-lib_3-0.9.1-sources.jar (OPTIONAL)
├── os-lib_3-0.9.1.jar
└── os-lib_3-0.9.1.pom

Path on MacOS ~/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/lihaoyi/os-lib_3/0.9.1

The first segments after the v1 directory are the address of the repository from which the artifact was downloaded. This part can effectively be https/repo1.maven.org/maven2 since maven central is the default repository to use. The rest of the path is the artifact's organization (split by the '.' character) and version.

Testing offline mode

To perform a test of environment setup for offline mode, it may be useful to create a clean cache directory for coursier. To do so, run:

mkdir test-coursier-cache
export COURSIER_CACHE=`pwd`/test-coursier-cache

And proceed with setting up the environment as described above:

# Should fail with:
# [error] Error downloading org.scala-lang:scala3-compiler_3:3.3.0
scala-cli run Main.scala --jvm 11 --offline
cs install scala:3.3.0 scalac:3.3.0

# Could fail with:
# Error while getting https://github.com/coursier/jvm-index/raw/master/index.json
# But may also pass on MacOS ('/usr/libexec/java_home -v' is tried)
# or if a JVM is cached in coursier's archive cache (this cache's location can't be overridden), you may want to clear it, see section below
scala-cli run Main.scala --jvm 11 --offline
cs java --jvm 11

# Should pass with a warning:
# [warn] Offline mode is ON and Bloop could not be fetched from the local cache, using scalac as fallback
scala-cli run Main.scala --jvm 11 --offline
cs fetch io.github.alexarchambault.bleep:bloop-frontend_2.12:1.5.11-sc-3

# Should pass with a warning:
# [warn] Offline mode is ON and a JVM for Bloop could not be fetched from the local cache, using scalac as fallback
scala-cli run Main.scala --jvm 11 --offline
cs java 17

Should pass with no warnings
scala-cli run Main.scala --jvm 11 --offline

Clearing coursier's caches

Citing Coursier's docs:
On a system where only recent versions of coursier were ever run (>= 1.0.0-RC12-1, released on the 2017/10/31), the default cache location is platform-dependent:

  • on Linux, ~/.cache/coursier/v1. This also applies to Linux-based CI environments, and FreeBSD too
  • on OS X, ~/Library/Caches/Coursier/v1
  • on Windows, %LOCALAPPDATA%\Coursier\Cache\v1, which, for user Alex, typically corresponds to C:\Users\Alex\AppData\Local\Coursier\Cache\v1

So clearing the cache is just a matter of removing the v1 directory corresponding to the platform you're on. However, Coursier does use a second archive cache, which should be located in the same place as the v1 directory, e.g. ~/.cache/coursier/arc, this cache's location can't be overridden, so it may be necessary to clear it for proper testing.