1. Sequencing

Sequencing 

One of the most frequently asked questions is in the form of “how do I do X and then do Y in sbt”?

Generally speaking, that’s not how sbt tasks are set up. build.sbt is a DSL to define dependency graph of tasks. This is covered in Execution semantics of tasks. So ideally, what you should do is define task Y yourself, and depend on the task X.

taskY := {
  val x = taskX.value
  x + 1
}

This is more constrained compared to the imperative style plain Scala code with side effects such as the follows:

def foo(): Unit = {
  doX()
  doY()
}

The benefit of the dependency-oriented programming model is that sbt’s task engine is able to reorder the task execution. When possible we run dependent tasks in parallel. Another benefit is that we can deduplicate the graph, and make sure that the task evaluation, such as Compile / compile, is called once per command execution, as opposed to compiling the same source many times.

Because task system is generally set up this way, running something sequentially is possible, but you will be fighting the system a bit, and it’s not always going to be easy.