Documentation Index
Fetch the complete documentation index at: https://mintlify.com/sbt/sbt/llms.txt
Use this file to discover all available pages before exploring further.
Overview
An sbt build is defined by one or more .sbt files in the project’s base directory, optionally combined with Scala source files in the project/ directory for more complex configuration.
build.sbt Files
The build.sbt file in the project root is the primary build definition file. It uses a Scala-based DSL to configure your build.
Basic Structure
name := "my-project"
version := "1.0.0"
scalaVersion := "2.13.12"
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.3.0"
Each line in build.sbt is a setting expression. Settings are separated by blank lines (not semicolons).
Real-World Example
From the sbt source code itself (build.sbt:1-50):
import Dependencies.*
// ThisBuild settings take lower precedence,
// but can be shared across the multi projects.
ThisBuild / version := {
val v = "2.0.0-RC9-bin-SNAPSHOT"
nightlyVersion.getOrElse(v)
}
ThisBuild / organization := "org.scala-sbt"
ThisBuild / description := "sbt is an interactive build tool"
ThisBuild / licenses := List(
"Apache-2.0" -> url("https://github.com/sbt/sbt/blob/develop/LICENSE")
)
ThisBuild / javacOptions ++= Seq("-source", "1.8", "-target", "1.8")
ThisBuild / Compile / doc / javacOptions := Nil
Settings defined with ThisBuild / apply to all subprojects in a multi-project build.
Project Directory
For more complex build logic, you can write Scala code in project/*.scala files. This is where you define project definitions, custom tasks, and build-level utilities.
Project Definition Example
From sbt’s source (main-settings/src/main/scala/sbt/Project.scala:129-154):
sealed trait Project extends ProjectDefinition[ProjectReference] {
/** Adds new configurations directly to this project. */
def configs(cs: Configuration*): Project =
copy(configurations = configurations ++ cs)
/** Adds classpath dependencies on internal or external projects. */
def dependsOn(deps: ClasspathDep[ProjectReference]*): Project =
copy(dependencies = dependencies ++ deps)
/** Adds projects to be aggregated. */
def aggregate(refs: ProjectReference*): Project =
copy(aggregate = (aggregate: Seq[ProjectReference]) ++ refs)
/** Appends settings to the current settings sequence. */
def settings(ss: Def.SettingsDefinition*): Project =
copy(settings = (settings: Seq[Def.Setting[?]]) ++ Def.settings(ss*))
/** Sets the base directory for this project. */
infix def in(dir: File): Project = copy(base = dir)
}
Creating Projects in Scala
From the sbt build (build.sbt:164-217):
lazy val sbtRoot: Project = (project in file("."))
.aggregate(
(allProjects diff Seq(lmCoursierShaded))
.map(p => LocalProject(p.id))*
)
.settings(
minimalSettings,
onLoadMessage := """Welcome to the build for sbt.""",
publishLocal := {},
mimaPreviousArtifacts := Set.empty
)
lazy val collectionProj = project
.in(file("util-collection"))
.dependsOn(utilPosition, utilCore)
.settings(
name := "Collections",
testedBaseSettings,
libraryDependencies ++= Seq(sjsonNewScalaJson.value),
mimaSettings
)
Build Definition Components
Settings vs Tasks
Settings are evaluated once at project load time:
name := "my-project" // Setting
scalaVersion := "3.3.1" // Setting
Tasks are evaluated on demand:
compile := { /* compilation logic */ } // Task
packageBin := { /* packaging logic */ } // Task
Common Settings
From sbt’s Keys.scala, here are commonly used settings:
// Project identification (Keys.scala:78-86)
val thisProject = settingKey[ResolvedProject](
"Provides the current project for the referencing scope."
)
val thisProjectRef = settingKey[ProjectRef](
"Provides a fully-resolved reference to the current project."
)
// Paths (Keys.scala:147-154)
val baseDirectory = settingKey[File](
"The base directory. Depending on the scope, this is the base directory for the build, project, configuration, or task."
)
val target = settingKey[File](
"Main directory for files generated by the build."
)
val sourceDirectory = settingKey[File](
"Default directory containing sources."
)
Build Structure
A typical sbt project structure:
project-root/
├── build.sbt # Primary build definition
├── project/
│ ├── build.properties # sbt version
│ ├── plugins.sbt # sbt plugin dependencies
│ └── Build.scala # (optional) Complex build logic
├── src/
│ ├── main/
│ │ ├── scala/ # Main Scala sources
│ │ └── resources/ # Main resources
│ └── test/
│ ├── scala/ # Test Scala sources
│ └── resources/ # Test resources
└── target/ # Generated files
Do not edit files in the target/ directory - they are generated by the build and will be deleted by clean.
Loading Process
When sbt loads a build:
- Reads
project/build.properties to determine sbt version
- Loads plugin definitions from
project/*.sbt and project/*.scala
- Compiles
project/*.scala files
- Evaluates
build.sbt using the compiled project definition
- Resolves all settings and creates the build structure
Best Practices
Keep build.sbt simple: For most projects, build.sbt alone is sufficient. Only use project/*.scala when you need complex logic, custom tasks, or shared build utilities.
Use blank lines as separators: In .sbt files, settings must be separated by at least one blank line. This is a syntactic requirement, not just style.
// Correct
name := "project"
version := "1.0"
// Incorrect - missing blank lines
name := "project"
version := "1.0"
References