Manage SBT dependencies from a single YAML file with version markers, auto-updates, and cross-project support
- Manage all dependencies in a single
project/dependencies.conffile (HOCON format). - Update dependencies to their latest versions with a single command.
- Control updates with version markers: pin, restrict to major, or restrict to minor.
- Document pinning decisions with dependency notes.
- Mark dependencies as intransitive to exclude transitive dependencies.
- Automatically migrate renamed artifacts using Scala Steward's migration list.
- Exclude known-bad versions from updates using Scala Steward's ignore list.
- Automatically exclude retracted versions from updates using Scala Steward's retraction list.
- Pin updates to allowed versions using Scala Steward's pin list.
- Generate post-update hooks and scalafix migrations for CI automation using Scala Steward's configuration.
- Manage Scala versions, SBT version, and Scalafmt version from the same workflow.
- Share versions across dependencies with version variables, including BOM support.
- VS Code / Cursor extension with syntax highlighting for
dependencies.conf.
Add the following line to your project/project/plugins.sbt file:
addSbtPlugin("com.alejandrohdezma" % "sbt-dependencies" % "0.19.2")Adding the plugin to
project/project/plugins.sbt(meta-build) allows it to manage both your build dependencies and your project dependencies.
This plugin manages your project's dependencies through a single project/dependencies.conf file. Instead of declaring libraryDependencies and addSbtPlugin in your build files, you list all dependencies in HOCON format grouped by project name:
sbt-build = [
"ch.epfl.scala:sbt-scalafix:0.14.5:sbt-plugin"
"org.scalameta:sbt-scalafmt:2.5.4:sbt-plugin"
]
my-project = [
"org.typelevel::cats-core:2.10.0"
"org.scalameta::munit:1.2.1:test"
]The plugin automatically populates libraryDependencies for each project based on its group and provides commands to install, update, and validate dependencies.
- Installation
- Usage
- How to...
- Migrate an existing project
- Define dependencies
- Use cross-compiled (Scala) dependencies
- Filter dependencies by Scala version
- Pin a dependency to a specific version
- Add a note to a pinned dependency
- Mark a dependency as intransitive
- Use shared version variables
- Configure Scala versions
- Use the advanced group format
- Install a new dependency
- Install a build dependency
- Update project dependencies
- Update only specific dependencies
- Update build dependencies
- Update Scala versions
- Update the SBT version
- Update the scalafmt version
- Update the plugin itself
- Update everything at once
- Configure artifact migrations
- Configure update ignores
- Configure retracted versions
- Configure update pins
- Configure post-update hooks
- Configure scalafix migrations
- Show library dependencies
- Get all resolved dependencies
- Validate resolved dependencies
- Disable eviction warnings
- VS Code / Cursor Extension
An extension for VS Code and Cursor is available that provides syntax highlighting for dependencies.conf files. It highlights organizations, artifacts, versions, version markers, configurations, variable references, and comments.
See the extension's README for installation and usage instructions.
Migrate an existing project
Run initDependenciesFile to automatically generate dependencies.conf from your current libraryDependencies and addSbtPlugin settings:
sbt> initDependenciesFileAfter running this command, remove the libraryDependencies += and addSbtPlugin lines from your build files, as the plugin will now manage them via dependencies.conf.
Define dependencies
Create a project/dependencies.conf file listing your dependencies. Groups correspond to:
sbt-build: Dependencies for your build definition (plugins and libraries used inbuild.sbt)<project-name>: Dependencies for a specific project (matches the SBT project name)
Dependencies follow this format:
org::name:version:config # Cross-compiled (Scala) dependency with configuration
org::name:version # Cross-compiled (Scala) dependency
org::name # Cross-compiled, latest version resolved automatically
org:name:version:config # Java dependency with configuration
org:name:version # Java dependency
org:name # Java, latest version resolved automatically
Supported configurations: compile (default), test, provided, sbt-plugin, etc.
Use cross-compiled (Scala) dependencies
Use :: (double colon) between organization and artifact name to indicate a Scala cross-compiled dependency. This is equivalent to %% in SBT:
my-project = [
"org.typelevel::cats-core:2.10.0" # Cross-compiled (like org.typelevel %% "cats-core")
"com.google.guava:guava:33.0.0" # Java dependency (like com.google.guava % "guava")
]Filter dependencies by Scala version
Dependencies with Scala version suffixes in their artifact name are automatically filtered based on the current scalaVersion:
my-project = [
"org.example:my-lib_2.13:1.0.0" # Only added when scalaVersion is 2.13.x
"org.example:my-lib_2.12:1.0.0" # Only added when scalaVersion is 2.12.x
"org.example:my-lib_3:1.0.0" # Only added when scalaVersion is 3.x
"org.example:other-lib:1.0.0" # Always added (no suffix)
]This is useful for dependencies that are published with Scala-specific variants but aren't cross-compiled in the usual way (e.g., some native libraries or Java libraries with Scala-specific modules).
Pin a dependency to a specific version
Control how dependencies are updated using version markers:
| Marker | Example | Behavior |
|---|---|---|
| (none) | 2.10.0 |
Update to latest compatible version |
= |
=2.10.0 |
Pin to exact version, never update |
^ |
^2.10.0 |
Update within major version only (2.x.x) |
~ |
~2.10.0 |
Update within minor version only (2.10.x) |
my-project = [
"org.typelevel::cats-core:2.10.0" # Will update to any newer version
"org.typelevel::cats-effect:=3.5.0" # Pinned, never updated
"co.fs2::fs2-core:^3.9.0" # Updated within 3.x.x only
"io.circe::circe-core:~0.14.6" # Updated within 0.14.x only
]Add a note to a pinned dependency
When pinning a dependency with a version marker, you can add a note explaining why using an object format:
my-project = [
{ dependency = "org.typelevel::cats-core:=2.10.0", note = "v3 drops Scala 2.12" }
]Long notes are automatically formatted across multiple lines:
my-project = [
{
dependency = "org.http4s::http4s-core:~0.21.34"
note = "Pinned to 0.21.x because the EntityEncoder changes in 0.22 require a full rewrite of our streaming layer"
}
]Both formats (plain strings and objects with notes) can coexist in the same dependency list. Notes are preserved through updateDependencies — only the version is updated while the note remains unchanged.
Mark a dependency as intransitive
Use the object format with intransitive = true to exclude transitive dependencies:
my-project = [
{ dependency = "org.http4s::http4s-core:0.23.3", intransitive = true }
]This applies .intransitive() to the ModuleID, preventing SBT from pulling in its transitive dependencies.
You can combine intransitive with a note to document why:
my-project = [
{ dependency = "org.http4s::http4s-core:0.23.3", intransitive = true, note = "We only need the core types" }
]Both single-line and multi-line formats are supported. Long entries are automatically formatted across multiple lines:
my-project = [
{
dependency = "org.http4s::http4s-core:0.23.3"
note = "We only need the core types, transitive deps conflict with our custom HTTP layer"
intransitive = true
}
]The intransitive flag is preserved through updateDependencies — only the version is updated.
Use shared version variables
You can use variable syntax to reference versions defined (or computed) in your build:
my-project = [
"org.typelevel::cats-core:{{catsVersion}}"
"org.typelevel::cats-effect:{{catsVersion}}"
]Define variable resolvers in your build.sbt:
dependencyVersionVariables := Map(
"catsVersion" -> { artifact => artifact % "2.10.0" }
)When running updateDependencies, variable-based dependencies show their resolved version and the latest available version, but the variable reference is preserved in the file.
Using with here-sbt-bom
The here-sbt-bom plugin reads Maven BOM files and exposes version constants. You can reference these in your dependencies.conf:
my-project = [
"com.fasterxml.jackson.core:jackson-core:{{jackson}}"
"com.fasterxml.jackson.core:jackson-databind:{{jackson}}"
]// build.sbt
val jacksonBom = Bom("com.fasterxml.jackson" % "jackson-bom" % "2.14.2")
dependencyVersionVariables := Map(
"jackson" -> { artifact => artifact % jacksonBom.key.value }
)Configure Scala versions
You can configure scalaVersion and crossScalaVersions directly in dependencies.conf using the advanced format:
sbt-build {
scala-versions = ["2.13.12", "2.12.18"]
dependencies = [
"ch.epfl.scala:sbt-scalafix:0.14.5:sbt-plugin"
]
}
my-project {
scala-version = "3.3.1"
dependencies = [
"org.typelevel::cats-core:2.10.0"
]
}Use scala-version (singular) for a single version or scala-versions (plural) for cross-building.
Behavior:
- The first version becomes
scalaVersion - All versions become
crossScalaVersions scala-version/scala-versionsin thesbt-buildgroup applies at the build level (ThisBuild / scalaVersionandThisBuild / crossScalaVersions)scala-version/scala-versionsin individual project groups overrides the build-level settings for that project
This allows you to set a default Scala version for all projects while letting specific projects use different versions.
Use the advanced group format
Groups support an advanced format that enables additional configuration beyond just listing dependencies:
my-project {
scala-versions = ["2.13.12", "2.12.18", "3.3.1"]
dependencies = [
"org.typelevel::cats-core:2.10.0"
"org.scalameta::munit:1.2.1:test"
]
}The simple format (array of dependencies) and advanced format (object with dependencies key) can be mixed in the same file.
Install a new dependency
Use install to add a new dependency to the current project's group in dependencies.conf:
sbt> install org.typelevel::cats-core:2.10.0
sbt> install org.typelevel::cats-effect # Resolves latest version
sbt> install org.scalameta::munit:1.2.1:testInstall a build dependency
Use installBuildDependencies to add a new dependency to the meta-build (sbt-build group):
sbt> installBuildDependencies ch.epfl.scala:sbt-scalafix:0.14.5:sbt-pluginUpdate project dependencies
Use updateDependencies to update dependencies in the current project to their latest versions (respecting version markers):
sbt> updateDependenciesUpdate only specific dependencies
Pass a filter to updateDependencies to update only matching dependencies:
sbt> updateDependencies org.typelevel: # Update all org.typelevel dependencies
sbt> updateDependencies :cats-core # Update cats-core from any organization
sbt> updateDependencies org.typelevel:cats-core # Update a specific dependencyUpdate build dependencies
Use updateBuildDependencies to update dependencies in the meta-build (project/dependencies.conf, group sbt-build):
sbt> updateBuildDependenciesUpdate Scala versions
Use updateScalaVersions to update Scala versions in the current project to their latest versions within the same minor line:
sbt> updateScalaVersionsEach version is updated within its minor line:
2.13.12→ latest2.13.x2.12.18→ latest2.12.x3.3.1→ latest3.3.x
Use updateBuildScalaVersions to update Scala versions in the sbt-build group (build-level settings):
sbt> updateBuildScalaVersionsUpdate the SBT version
Use updateSbt to update the SBT version in project/build.properties to the latest version. If updated, it triggers a reboot to apply the new version.
sbt> updateSbtUpdate the scalafmt version
Use updateScalafmtVersion to update the scalafmt version in .scalafmt.conf to the latest version:
sbt> updateScalafmtVersionUpdate the plugin itself
Use updateSbtPlugin to update the sbt-dependencies plugin itself in project/project/plugins.sbt:
sbt> updateSbtPluginWrapper plugins can override which plugin gets updated by setting these keys in their own buildSettings:
sbtDependenciesPluginOrganization := "com.example"
sbtDependenciesPluginName := "sbt-my-plugin"Update everything at once
Use updateAllDependencies to update the plugin itself, Scala versions, dependencies, scalafmt version, and the SBT version all at once:
sbt> updateAllDependenciesConfigure artifact migrations
When running updateDependencies, the plugin automatically detects when a dependency has moved to new coordinates (new groupId or artifactId) and migrates it. This follows the same artifact migrations scheme as Scala Steward and uses Scala Steward's artifact migration list by default.
Migrated dependencies are shown with a 🔀 indicator:
↳ 🔀 org.json4s::json4s-core:4.0.7 -> io.github.json4s::json4s-core:4.1.0
You can customize the migration sources using the dependencyMigrations setting:
// Disable all migrations
ThisBuild / dependencyMigrations := Nil
// Add a custom migrations URL
ThisBuild / dependencyMigrations += url("https://example.com/my-migrations.conf")
// Use a local file
ThisBuild / dependencyMigrations := List(file("project/artifact-migrations.conf").toURI.toURL)Custom migration files use Scala Steward's HOCON format:
changes = [
{
groupIdBefore = org.json4s
groupIdAfter = io.github.json4s
artifactIdAfter = json4s-core
}
]Each entry supports groupIdBefore, groupIdAfter, artifactIdBefore, and artifactIdAfter. At least one of groupIdBefore or artifactIdBefore must be defined.
Configure update ignores
When running update commands (updateDependencies, updateScalaVersions, updateSbt, updateScalafmtVersion, updateSbtPlugin), the plugin automatically excludes known-bad dependency versions from update candidates. This follows the same updates.ignore format as Scala Steward and uses Scala Steward's default configuration by default.
You can customize the ignore sources using the dependencyUpdateIgnores setting:
// Disable all ignores
ThisBuild / dependencyUpdateIgnores := Nil
// Add a custom ignore URL
ThisBuild / dependencyUpdateIgnores += url("https://example.com/my-ignores.conf")
// Use a local file
ThisBuild / dependencyUpdateIgnores += file("ignores.conf").toURI.toURLCustom ignore files use Scala Steward's HOCON format:
updates.ignore = [
{ groupId = "org.scala-lang", artifactId = "scala3-compiler", version = { exact = "3.8.2" } }
{ groupId = "org.scala-lang", artifactId = "scala-compiler", version = "2.13." }
{ groupId = "com.typesafe.akka" }
]Each entry requires a groupId. The artifactId and version fields are optional:
- If
artifactIdis omitted, all artifacts in the group are matched. - If
versionis omitted, all versions are matched. versioncan be a string (treated as a prefix) or an object withexact,prefix,suffix, orcontainsfields.
Configure retracted versions
When running update commands, the plugin automatically excludes retracted (broken) dependency versions from update candidates. This follows the same updates.retracted format as Scala Steward and uses Scala Steward's default configuration by default.
When a dependency's current version is retracted, a warning is logged with the reason and a link to documentation.
You can customize the retraction sources using the dependencyUpdateRetractions setting:
// Disable all retractions
ThisBuild / dependencyUpdateRetractions := Nil
// Add a custom retraction URL
ThisBuild / dependencyUpdateRetractions += url("https://example.com/my-retractions.conf")
// Use a local file
ThisBuild / dependencyUpdateRetractions += file("retractions.conf").toURI.toURLCustom retraction files use Scala Steward's HOCON format:
updates.retracted = [
{
reason = "Broken binary compatibility"
doc = "https://example.com/issue/123"
artifacts = [
{ groupId = "org.example", artifactId = "my-lib", version = { exact = "1.2.0" } }
]
}
]Each entry requires a reason and a doc URL. The artifacts array uses the same pattern as update ignores: groupId (required), artifactId (optional), and version (optional, string or object with exact/prefix/suffix/contains).
Configure update pins
When running update commands (updateDependencies, updateScalaVersions, updateSbt, updateScalafmtVersion, updateSbtPlugin), the plugin can restrict updates to versions matching a pin's version pattern. This follows the same updates.pin format as Scala Steward and uses Scala Steward's default configuration by default.
Unlike ignores (which exclude specific versions), pins act as a whitelist: only versions matching the pin's pattern are allowed for matching artifacts. Artifacts without a matching pin are unaffected.
You can customize the pin sources using the dependencyUpdatePins setting:
// Disable all pins
ThisBuild / dependencyUpdatePins := Nil
// Add a custom pin URL
ThisBuild / dependencyUpdatePins += url("https://example.com/my-pins.conf")
// Use a local file
ThisBuild / dependencyUpdatePins += file("pins.conf").toURI.toURLCustom pin files use Scala Steward's HOCON format:
updates.pin = [
{ groupId = "org.http4s", version = "0.23." }
{ groupId = "org.typelevel", artifactId = "cats-core", version = { prefix = "2." } }
]Each entry requires a groupId. The artifactId and version fields are optional:
- If
artifactIdis omitted, all artifacts in the group are matched. - If
versionis omitted, all versions are allowed (the pin has no effect). versioncan be a string (treated as a prefix) or an object withexact,prefix,suffix, orcontainsfields.
Configure post-update hooks
When updateAllDependencies runs, it generates a JSON file at target/sbt-dependencies/.sbt-post-update-hooks listing scripts that should be run after updating. This is useful for CI automation — for example, running sbt scalafixAll after updating a dependency that ships scalafix rewrite rules, or sbt headerCreateAll after updating sbt-header.
The hooks are loaded from Scala Steward's postUpdateHooks configuration by default. Each hook specifies a groupId/artifactId filter and a command to run when a matching dependency is updated.
The output file is a JSON array, parseable with jq or similar tools:
[
{"script": "sbt scalafixAll", "message": "Reorganize imports with OrganizeImports 0.6.0"},
{"script": "sbt headerCreateAll", "message": "Update file headers with sbt-header 1.2.0"}
]You can customize the hook sources using the dependencyPostUpdateHooks setting:
// Disable all hooks
ThisBuild / dependencyPostUpdateHooks := Nil
// Add a custom hooks URL
ThisBuild / dependencyPostUpdateHooks += url("https://example.com/my-hooks.conf")
// Use a local file
ThisBuild / dependencyPostUpdateHooks += file("hooks.conf").toURI.toURLCustom hook files use Scala Steward's HOCON format:
postUpdateHooks = [
{
groupId = "com.github.liancheng"
artifactId = "organize-imports"
command = ["sbt", "scalafixAll"]
commitMessage = "Run OrganizeImports after updating to ${nextVersion}"
}
]Each entry supports groupId (optional), artifactId (optional), command (string array, required), and commitMessage (required). The commit message supports ${nextVersion}, ${currentVersion}, and ${artifactName} variables.
Configure scalafix migrations
When updateAllDependencies runs, it also matches Scala Steward's scalafix migrations against updated dependencies. When a dependency update crosses a migration's version threshold, the corresponding scalafix rule is included in the post-update hooks output.
The generated scripts are scoped to the project where the dependency was updated:
[
{"script": "sbt \"scalafixEnable; core/scalafixAll github:typelevel/cats/Cats_v2_2_0?sha=v2.2.0\"", "message": "Run scalafix migration in core: Cats_v2_2_0 (see https://github.com/typelevel/cats/...)"}
]For build-level dependencies (plugins in the sbt-build group), migrations run the scalafix CLI directly on build files instead:
[
{"script": "scalafix --rules=Sbt0_13BuildSyntax", "message": "Run scalafix migration (build): Sbt0_13BuildSyntax"}
]When a migration requires extra scalac options (e.g., -P:semanticdb:synthetics:on), they are included in the sbt command automatically.
You can customize the migration sources using the dependencyScalafixMigrations setting:
// Disable all scalafix migrations
ThisBuild / dependencyScalafixMigrations := Nil
// Add a custom migrations URL
ThisBuild / dependencyScalafixMigrations += url("https://example.com/my-migrations.conf")
// Use a local file
ThisBuild / dependencyScalafixMigrations += file("migrations.conf").toURI.toURLCustom migration files use Scala Steward's HOCON format:
migrations = [
{
groupId: "org.typelevel"
artifactIds: ["cats-core"]
newVersion: "2.2.0"
rewriteRules: ["github:typelevel/cats/Cats_v2_2_0?sha=v2.2.0"]
doc: "https://github.com/typelevel/cats/blob/v2.2.0/scalafix/README.md"
scalacOptions: ["-P:semanticdb:synthetics:on"]
}
]Each entry requires groupId, artifactIds (regex patterns), newVersion, and rewriteRules. The doc and scalacOptions fields are optional. A migration triggers when the dependency's version crosses newVersion (i.e., currentVersion < newVersion <= nextVersion).
Show library dependencies
Use showLibraryDependencies to display the library dependencies for the current project in a formatted, colored output. It shows both direct dependencies and those inherited from dependent projects (via .dependsOn).
sbt> showLibraryDependencies- Green = direct dependencies
- Yellow = inherited from other projects
Get all resolved dependencies
Use allProjectDependencies to get the complete list of resolved library dependencies for the project after conflict resolution and eviction:
sbt> show allProjectDependenciesThis is useful for programmatic access to dependencies in custom tasks or checks.
Validate resolved dependencies
Use dependenciesCheck to register custom check functions that validate resolved dependencies after update. If any check throws, the build fails.
// build.sbt
dependenciesCheck += { (deps: List[ModuleID]) =>
if (deps.exists(_.name.contains("log4j")))
throw new MessageOnlyException("log4j is banned - use logback instead")
}Each function receives the full list of resolved ModuleIDs after conflict resolution and eviction.
Disable eviction warnings
Use disableEvictionWarnings to downgrade eviction errors to info level, preventing them from failing the build:
sbt> disableEvictionWarningsTo restore eviction warnings to error level (default behavior), use enableEvictionWarnings:
sbt> enableEvictionWarnings| alejandrohdezma |