Read Scopes for the full explanation.
I'll quote relevant parts:
There are three scope axes:
- The subproject axis
- The dependency configuration axis
- The task axis
Scoping by project axis
If you put multiple projects in a single build, each project needs its own settings. That is, keys can be scoped according to the project.
The project axis can also be set to ThisBuild
, which means the “entire build”, so a setting applies to the entire build rather than a single project. Build-level settings are often used as a fallback when a project doesn’t define a project-specific setting.
Zero scope component
Each scope axis can be filled in with an instance of the axis type (analogous to Some(_)
), or the axis can be filled in with the special value Zero
. So we can think of Zero
as None
.
Zero
is a universal fallback for all scope axes, but its direct use should be reserved to sbt and plugin authors in most cases.
Global
is a scope that sets Zero
to all axes: Zero / Zero / Zero
. In other words, Global / someKey
is a shorthand for Zero / Zero / Zero / someKey
.
Referring to scopes in a build definition
Global / concurrentRestrictions := Seq(
Tags.limitAll(1)
)
(Global / concurrentRestrictions
implicitly converts to Zero / Zero / Zero / concurrentRestrictions
, setting all axes to Zero
scope component; the task and configuration are already Zero
by default, so here the effect is to make the project Zero
, that is, define Zero / Zero / Zero / concurrentRestrictions
rather than ProjectRef(uri("file:/tmp/hello/"), "root") / Zero / Zero / concurrentRestrictions
)
So as written above, Global
sets all three axes to Zero
whereas ThisBuild
sets only the subproject axis to ThisBuild
. This might make sense if you combine ThisBuild
with other axis like configuration:
> set ThisBuild / Test / name := "test-name"
[info] Defining ThisBuild / Test / name
Update February 2020: As Stefan K noted in the comment scope delegation rule is a key fact that I didn't include in the above explanation.
Rule 4: Given a scope, delegate scopes are searched by substituting the subproject axis in the following order: the given subproject, ThisBuild
, and then Zero
.
For example, if publishing configuration refers to projFoo / version
, it would look in the order of:
projFoo / version
ThisBuild / version
Global / version
If the default setting is scoped to Global
, like in the case of version
setting (see inspect version
), using either ThisBuild / version
or Global / version
would be able to set a version number for all projects in the build. The choice of ThisBuild
here is almost by convention.
There are times where one might want to distinguish the two scoping. First is for source dependencies. sbt has a built-in support to depend on subprojects across multiple builds. In these cases, using ThisBuild
would prevent one setting from spilling over to other builds.
There are also cases where some feature specifically refers to a globally scoped setting, often to configure the behavior of a command and/or the behavior of sbt itself. Global / concurrentRestrictions
is an example of that. In this case, one must use Global / concurrentRestrictions
.