sbt-extras: a shell script that guesses which sbt and Scala your project wants
A more featureful runner for sbt, the simple/scala/standard build tool
At a glance
- What is it?
- sbt-extras is a self-contained shell script that replaces the sbt launcher, detects the sbt and Scala versions a project declares, downloads them if they are missing, and gives you a single dash option namespace for JVM, launcher and cache settings. The trade-off is a script that sits between you and the official launcher.
- Who is it for?
- sbt-extras is worth adopting for teams that juggle several sbt and Scala versions across a machine, where the version resolution and the per project JVM options it provides save more time than the script costs. It is the wrong choice if you want the official sbt distribution unchanged, or if your environment blocks the downloads to repo.scala-sbt.org that the launcher path depends on.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 54 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A single file that stands in for the sbt launcher
sbt-extras is an alternative script for running sbt, and the README describes it as working with sbt 1 projects and, in principle, all earlier versions. The whole thing is a self-contained shell script that you drop somewhere on your path, and its job is to stand between you and the official sbt launcher. The interesting part is what it does before sbt starts. If you are in an sbt project directory, the script figures out the required versions of sbt and Scala and downloads them if necessary. The repository is small and mostly script: a top-level sbt script, a bin directory, a test directory and a README. There is no daemon, no configuration format of its own and no plugin system, which is exactly why it is easy to adopt and also exactly why it cannot do more than launch. The audience is a Scala developer on a machine where different projects pin different sbt and Scala versions, and where the JVM options for one project should not leak into the next.
Single dash for the runner, double dash for sbt itself
The option namespace is where sbt-extras differs most sharply from the official launcher, and the rule is stated plainly in the help text. Options passed along to sbt begin with a double dash, while options to this runner use a single dash. Anything that looks like it might be special can be forced through to sbt by prefixing it with a double dash, so --warn and --error are forwarded rather than interpreted. That solves a real problem, because the help text lists -d, -w and -q as aliases for the double dash forms --debug, --warn and --error. The help listing is short and dense, and the debug switch for the script itself sits next to the verbosity switch.
-h | -help print this message
-v verbose operation (this runner is chattier)
-d, -w, -q aliases for --debug, --warn, --error (q means quiet)
-x debug this scriptHow the version of sbt gets decided
The default sbt version comes from sbt.version in project/build.properties when that file is present, and otherwise from a built-in default, which the help text lists as 1.13.0. You can override it outright with -sbt-version, ask for the latest release with -sbt-force-latest, or ask for the latest pre-release with -sbt-dev. Two more switches exist for unusual setups: -sbt-jar points the script at a specific jar to use as the launcher, and -sbt-create starts sbt even when the current directory contains no sbt project. The Scala side is handled by numbered flags, one per binary line.
# scala version (default: as chosen by sbt)
-28 use 2.8.2
-212 use 2.12.21
-213 use 2.13.12There is also a plain -scala-version flag and a -binary-version flag, which uses the given Scala version when searching for dependencies. The version numbers these flags resolve to are baked into the script, which means a new Scala release does not appear in the runner until the script is updated. A team that wants the newest patch of a line will find -scala-version more useful than the numbered shortcut.
-sbt-version <version> use the specified version of sbt (default: 1.13.0)
-sbt-force-latest force the use of the latest release of sbt: 1.13.0
-sbt-dev use the latest pre-release version of sbt: 1.13.0
-sbt-jar <path> use the specified jar as the sbt launcherThe launcher jar, the cache directories and the offline case
The script does not just pick a version, it manages where the pieces live. The launcher jar is kept in a launch directory, and the help text gives the default as ~/.sbt/launchers. A verbose run shows the resolved path directly, which is the first thing to check when a build behaves oddly on a new machine.
$HOME/.sbt/launchers/1.13.0/sbt-launch.jarThe download source is also configurable, with -sbt-launch-repo pointing at a different repository URL and the default given as the scala-sbt maven releases repository. On the cache side, -sbt-dir sets the global settings and plugins directory, which defaults to a versioned path under ~/.sbt, -sbt-boot sets the shared boot directory, and -ivy sets the local Ivy repository, defaulting to ~/.ivy2. Two flags matter on shared or locked down machines: -no-share uses all local caches with no sharing, and -offline puts sbt in offline mode, which is the switch to reach for on a machine with no outbound network.
-sbt-dir <path> path to global settings/plugins directory (default: ~/.sbt/<version>)
-sbt-boot <path> path to shared boot directory (default: ~/.sbt/boot in 0.11+)
-ivy <path> path to local Ivy repository (default: ~/.ivy2)
-no-share use all local caches; no sharing
-offline put sbt in offline modeJVM options come from a file, not from JAVA_OPTS
The JVM configuration story is the part where sbt-extras makes a deliberate choice that differs from the official launcher. The help text states that it does not use JAVA_OPTS, because of pollution, meaning a JAVA_OPTS variable set for one unrelated program leaks into your build. Instead the script defines a default set of arguments, and the JVM_OPTS variable can hold the arguments directly or a reference to a file when the path is prefixed with an @ sign, for example @'/etc/jvmopts'. A file named .jvmopts in the project root is picked up by default, and the -jvm-opts flag points at a specific file. The same pattern repeats for sbt options with SBT_OPTS and .sbtopts, and for the runner's own options with SBTX_OPTS and .sbtxopts, each overridable by a matching -sbt-opts or -sbtx-opts argument.
<default> -Xms512m -Xss2m -XX:MaxInlineLevel=18
JVM_OPTS environment variable holding either the jvm args directly, orTwo pass through flags cover the common cases: -Dkey=val passes a system property straight to the JVM, and -J-X passes an option to the JVM with the -J prefix stripped. On the sbt side, -S-X adds an option to scalacOptions with the -S prefix stripped. The practical upshot is that a per project JVM configuration becomes a checked in .jvmopts file, which is a better answer to a shared laptop than a global environment variable.
Installing the script and seeing what it decided
Installation is a single curl into a directory on your path, and the script is self-contained so there is nothing else to fetch.
curl -Ls https://raw.githubusercontent.com/dwijnand/sbt-extras/master/sbt > ~/bin/sbt && chmod 0755 ~/bin/sbtHomebrew is the other documented route, and it installs the script under a different name on purpose so it does not clash with the official sbt formula.
brew install --HEAD dwijnand/extras/sbtxThe README notes that the Homebrew install gives you the command sbtx and that you can alias sbt to it if you prefer. A first run with verbose output prints the decisions the script made, including the Scala version it injected and the sbt version it detected.
% sbt -v -212 -sbt-create about
[addSbt] arg = '++ 2.12.21'
[residual] arg = 'about'
No extra sbt options have been defined
Detected sbt version 1.13.0The same output also warns you when a project does not declare its sbt version, which is a useful signal on its own.
[warn] No sbt.version set in project/build.properties, base directory: [..]Interactive, scripted and non interactive modes
Several switches decide how much of a terminal session sbt gets. -batch disables interactive mode, which is the setting for CI. -prompt sets the sbt prompt from an expression in which s is the State and e is Extracted, so a team can put its own prompt into the console. -script runs a specific file as a scala script, and -jvm-debug turns on JVM debugging and opens the given port, which is how you attach a remote debugger to a build that hangs. -trace takes a level for stack traces with a maximum number of frames, defaulting to -1 with traces suppressed, and -no-colors disables ANSI colour codes, which matters when output is captured into a log. A developer who wants to know what the runner itself is doing rather than what sbt is doing uses -x, which debugs the script itself.
-batch Disable interactive mode
-prompt <expr> Set the sbt prompt; in expr, 's' is the State and 'e' is Extracted
-script <file> Run the specified file as a scala scriptLicence, release history and the state of the tree
The licence field on this repository is not a standard identifier, and the terms live in LICENSE.txt at the root, so anyone shipping sbt-extras inside a distribution should read that file rather than assume a permissive default. On releases, the repository has no GitHub releases at all, which means there are no tags to pin in a provisioning script and no changelog to consult when a behaviour changes. The project is not archived and the last push was on 2026-08-30, so the script is still being changed. The top level contents are minimal, an sbt script, a bin directory, a test directory, the licence and the README, and a test status badge in the project points at a Test workflow in the paulp/sbt-extras repository. The toolchain is a shell script, so the practical upgrade path is to re-run the curl command and diff the file, which is cheap but also means you have no version marker telling you what changed. For a team that wants a repeatable setup, pinning to a commit of your own fork and keeping the diff in the repository is more defensible than tracking a moving master branch.
Editorial conclusion
sbt-extras is worth adopting for teams that juggle several sbt and Scala versions across a machine, where the version resolution and the per project JVM options it provides save more time than the script costs. It is the wrong choice if you want the official sbt distribution unchanged, or if your environment blocks the downloads to repo.scala-sbt.org that the launcher path depends on. Before you switch, run the script with the -v flag in a project directory and read the detected sbt version and launcher path, then confirm that the version your build expects is the one the script picks up from project/build.properties.
Frequently asked questions
How do I install sbt-extras on my machine?
The README gives a curl command that writes the self-contained script to ~/bin/sbt and marks it executable, or a Homebrew install of dwijnand/extras/sbtx. The Homebrew route installs the command as sbtx so it does not clash with the official sbt formula.
How does sbt-extras choose which version of sbt to run?
It reads sbt.version from project/build.properties when the file is present and otherwise falls back to a built-in default listed as 1.13.0. The -sbt-version, -sbt-force-latest and -sbt-dev flags override that choice.
What is the difference between a single dash and a double dash in sbt-extras options?
Single dash options belong to the sbt-extras runner itself, while double dash options are passed along to sbt. Any sbt command can be scheduled to run first by prefixing it with a double dash, so --warn and --error are forwarded rather than treated as runner options.
Can I set JVM options per project with sbt-extras?
Yes. A .jvmopts file in the project root is used by default, the -jvm-opts flag points at a specific file, and the JVM_OPTS variable can hold arguments directly or a reference to a file prefixed with @. The script deliberately avoids JAVA_OPTS.
Does sbt-extras work offline on a machine with no network?
The runner exposes an -offline flag that puts sbt in offline mode, and the launcher jar location is configurable through -sbt-launch-dir while the download source is set by -sbt-launch-repo. The launchers directory defaults to ~/.sbt/launchers.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/dwijnand-sbt-extras)Was this useful?