# Projects with sbt — Scala

Source: https://www.geekswithgeeks.com/en/scala/e-sbt

> Structure multi-module builds, manage dependencies and run common tasks.

## Working with sbt

An **sbt** project has `build.sbt` at the root, `project/build.properties` pinning the sbt version, `project/plugins.sbt` for plugins, and sources in `src/main/scala` and `src/test/scala` (the Maven layout). Settings are key-value pairs such as `scalaVersion`, `libraryDependencies` and `scalacOptions`. **Multi-module builds** declare several `project`s with `dependsOn` between them, for example `domain`, `persistence` and `api`, to enforce architecture boundaries and speed up incremental compilation. Common tasks: `compile`, `test`, `testOnly *CartSpec`, `run`, `console` (a REPL with the project classpath), `reload` after changing the build and `~test` to rerun tests on every save. Useful plugins include **sbt-assembly** (fat JARs), **sbt-native-packager** (Docker images and archives), **sbt-scalafmt**, **sbt-scalafix**, **sbt-tpolecat** (strict compiler flags) and sbt-revolver. Enable compiler warnings as errors in CI (`-Werror`) along with `-Wunused:all`. Keep the build simple: most problems come from clever build logic, not from code.

## A multi-module build

Modules depend on each other in one direction, and sbt compiles each incrementally.

![Three stacked module boxes connected by downward arrows, with a build file icon on the side.](assets/figures/scala/section-7-map.svg) — Figure 7.1 — api depends on persistence, which depends on domain.

## A multi-module build.sbt

Shared settings, module dependencies and test libraries.

```scala
// build.sbt
ThisBuild / scalaVersion := "3.3.6"
ThisBuild / organization := "in.example"

lazy val commonSettings = Seq(
  scalacOptions ++= Seq("-deprecation", "-feature", "-Wunused:all"),
  libraryDependencies += "org.scalameta" %% "munit" % "1.1.0" % Test
)

lazy val domain = project
  .settings(commonSettings)

lazy val persistence = project
  .dependsOn(domain)
  .settings(
    commonSettings,
    libraryDependencies += "org.postgresql" % "postgresql" % "42.7.5"   // a Java library uses %
  )

lazy val api = project
  .dependsOn(domain, persistence)
  .settings(commonSettings)

lazy val root = (project in file("."))
  .aggregate(domain, persistence, api)      // sbt test runs tests in all modules

// project/build.properties:  sbt.version=1.10.11
// shell: sbt  then  ~api/test  or  testOnly *CartSuite
```

## % versus %%

Use `%%` for Scala libraries (published per Scala version) and a single `%` for plain Java libraries such as JDBC drivers. Using `%%` with a Java library fails to resolve.

**Quiz:** What does aggregate do in an sbt root project?

- [x] Runs tasks such as compile and test across the listed modules
- [ ] Merges all source files into one module
- [ ] Creates a fat JAR
- [ ] Downloads Scala

*Answer:* Runs tasks such as compile and test across the listed modules. Aggregation forwards tasks to the aggregated projects.
