Getting Started with SBT for Scala Project Builds

SBT (Simple Build Tool) is the standard build tool for Scala projects, comparable to Maven or Gradle in the Java ecosystem. It offers several key advantages:

  • Zero configuration reqiured for simple projects.
  • Build logic defined using Scala source code.
  • Precise incremental recompilation to save development time.
  • Library management powered by Coursier.
  • Seamless support for mixed Scala and Java projects.

Installation

SBT requires Java; ensure you have JDK 8 or newer installed. Download the installation package (e.g., version 1.5.5), extract it, and set the SBT_HOME environment variable. Add %SBT_HOME%\bin to your system PATH (installers often handle this automatically).

Basic Project Setup

Create a project directory and initialize the build file:

$ mkdir demo-project
$ cd demo-project
$ touch build.sbt

Launch the SBT interactive shell:

$ sbt
[info] Updated file /tmp/demo-project/project/build.properties: set sbt.version to 1.1.4
[info] Loading project definition from /tmp/demo-project/project
[info] Loading settings from build.sbt ...
[info] Set current project to demo-project (in build file:/tmp/demo-project/)
[info] sbt server started at local:///Users/user/.sbt/1.0/server/abc4fb6c89985a00fd95/sock
sbt:demo-project>

Note: The first initialization may take some time. Exit the shell with exit.

Common Shell Operations

  • compile: Compile the main sources.
  • run: Execute the main class.
  • ~ prefix (e.g., ~compile): Enter watch mode to automatically recompile on source changes. Press Enter to exit watch mode.
  • help: View general help; use help <command> for specific command details.
  • scalaVersion: Check the current Scala version.
  • Use Tab for command completion and arrow keys to navigate command history.

Adding Source Code

Keep ~compile running and create the standard source directory structure. Add a sample source file:

// src/main/scala/demo/Greeting.scala
package demo

object Greeting extends App {
  println("Welcome")
}

SBT will detect the change and recompile automatically.

Configuring Build Settings

Modify the Scala version temporarily in the shell:

sbt:demo-project> set ThisBuild / scalaVersion := "2.13.6"

Save the configuration to build.sbt:

sbt:demo-project> session save

A typical build.sbt file looks like this:

ThisBuild / scalaVersion := "2.13.6"
ThisBuild / organization := "com.demo"

lazy val greeting = (project in file("."))
  .settings(
    name := "Greeting"
  )

Reload the configuration with reload.

Testing with ScalaTest

Add ScalaTest as a test dependency in build.sbt:

ThisBuild / scalaVersion := "2.13.6"
ThisBuild / organization := "com.demo"

lazy val greeting = (project in file("."))
  .settings(
    name := "Greeting",
    libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.7" % Test
  )

Create a test file:

// src/test/scala/GreetingSpec.scala
import org.scalatest.funsuite._

class GreetingSpec extends AnyFunSuite {
  test("Greeting should start with G") {
    assert("Greeting".startsWith("G"))
  }
}

Run tests with test. Use ~testQuick to automatically run failed or updated tests on save.

Managing Dependencies

Add external libraries by appending to libraryDependencies:

lazy val greeting = (project in file("."))
  .settings(
    name := "Greeting",
    libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2",
    libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.7" % Test
  )

Using the Scala REPL

Launch the REPL with console. Inside the REPL:

  • :paste: Enter paste mode to paste multi-line code.
  • :q: Quit the REPL and return to the SBT shell.

Multi-Project Builds

Define subprojects in build.sbt:

ThisBuild / scalaVersion := "2.13.6"
ThisBuild / organization := "com.demo"

val scalaTest = "org.scalatest" %% "scalatest" % "3.2.7"

lazy val root = (project in file("."))
  .aggregate(core)
  .dependsOn(core)
  .settings(
    name := "RootProject",
    libraryDependencies += scalaTest % Test
  )

lazy val core = (project in file("core"))
  .settings(
    name := "CoreModule",
    libraryDependencies += scalaTest % Test
  )

After reload, the core/ directory is created. List projects with projects and compile the subproject with core/compile.

Packaging and Docker

Add the sbt-native-packager plugin in project/plugins.sbt:

addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.4")

Enable packaging in build.sbt:

lazy val root = (project in file("."))
  .aggregate(core)
  .dependsOn(core)
  .enablePlugins(JavaAppPackaging)
  .settings(...)

Create a ZIP distribution with dist. For Docker, use Docker/publishLocal and run with docker run rootproject:version.

Project Structure

SBT follows a structure similar to Maven:

src/
  main/
    resources/  # Files included in the main JAR
    scala/      # Main Scala sources
    java/       # Main Java sources
  test/
    resources/  # Test resources
    scala/      # Test Scala sources
    java/       # Test Java sources

Build definitions reside in build.sbt. The project/ directory can contain Scala files for custom build logic. Generated files are output to the target/ directory (add to .gitignore).

Running Commands Directly

Execute SBT commands without entering the shell (slower startup):

sbt clean "testOnly GreetingSpec"

Scaffolding New Projects

Use the new command with Giter8 templates:

$ sbt new scala/scala-seed.g8
name [My Something Project]: greeting
Template applied in ./greeting

Common Commands Reference

Command Description
clean Deletes all generated files in the target directory.
compile Compiles main sources in src/main.
test Compiles and runs all tests.
console Starts the Scala REPL with project dependencies.
run [args] Runs the project's main class with optional arguments.
package Creates a JAR file of the main sources and resources.
reload Reloads build.sbt and project definitions after changes.
++2.12.14 Temporarily switch the Scala version for the session.

Tags: Scala sbt Build Tools ScalaTest sbt-native-packager

Posted on Fri, 02 Oct 2026 16:24:54 +0000 by Haloscope