Docs menu
Package managers
How sbt resolves dependencies on Primcloud: the Ivy and Coursier caches, Maven and Ivy resolvers, private repositories, and lockfiles.
On this page
Scala on Primcloud has one build tool: sbt. sbt uses Coursier as its default resolver (with an Ivy fallback for older configurations), and it pulls from Maven-compatible repositories: Maven Central by default, plus anything you add in your build definition.
This page covers what happens during resolution, how to point sbt at a private repository, and how to opt into lockfile-enforced resolution.
The build tool#
sbt is the only build tool the Scala toolchain uses. A Maven or Gradle project deploys through the Java toolchain instead.
Under sbt, dependencies flow through two resolver stacks:
- Coursier: the default on sbt 1.3 and later.
- Ivy: used for older configurations and for sbt's own plugin resolution.
Primcloud keeps both caches warm between builds; see Scala on Primcloud → Caching.
When resolution happens#
There's no separate install step. sbt fetches dependencies on demand as part of the build:
sbt compile stage
compile resolves and pulls every libraryDependencies entry from build.sbt and every plugin from project/plugins.sbt. stage produces the runnable output your Procfile invokes. Both draw from the same cached Ivy and Coursier stores, which Primcloud wires sbt up to use automatically, so you don't set any cache paths yourself.
Private packages and registries#
Adding a resolver. Point sbt at a private repository in build.sbt, the same way you would locally:
resolvers += "My Private Repo" at "https://repo.example.com/maven"
For an Ivy-style repository:
resolvers += "My Ivy Repo" at "https://repo.example.com/ivy"
Credentials. Never commit credentials into a resolver URL. sbt reads them from a Credentials block in build.sbt or from ~/.sbt/.credentials. On Primcloud, drive both from environment variables set in the Secrets panel; they take effect on the next build.
Option 1: inline in build.sbt:
credentials += Credentials(
"My Private Repo",
"repo.example.com",
sys.env.getOrElse("PRIVATE_REPO_USERNAME", ""),
sys.env.getOrElse("PRIVATE_REPO_PASSWORD", "")
)
Then set PRIVATE_REPO_USERNAME and PRIVATE_REPO_PASSWORD in the Secrets panel.
Option 2: write a credentials file before resolution. Add a pre-task (see Customizing the build → Build hooks) that writes ~/.sbt/.credentials from environment variables before the build resolves.
The realm in the Credentials block has to match the value in the repository's WWW-Authenticate header. Get it wrong and resolution fails with 401 Unauthorized. The fix is to match the realm the repo actually advertises.
Coursier auth. For Sonatype-style repositories reached through Coursier, set COURSIER_CREDENTIALS:
COURSIER_CREDENTIALS=host=repo.example.com username=<user> password=<token>
Separate multiple credentials with whitespace. See the Coursier credentials docs for the full syntax.
Every secret you set on Primcloud is encrypted at rest and never printed in build logs.
Lockfiles#
sbt has no built-in lockfile the way npm or pip do. Two plugins add reproducible resolution, and both work on Primcloud with no extra configuration:
- sbt-lock: pins resolved versions to a
lock.sbt. Add it toproject/plugins.sbt, commit the generatedlock.sbt, and a later build fails if the lock disagrees with the resolved graph. - sbt-dependency-lock: a newer alternative with the same shape, using a
build.sbt.lock.
Both are opt-in, and both work because sbt runs on Primcloud exactly as it does locally; nothing rewrites resolution behind the scenes.
Without a lockfile, sbt still succeeds as long as the graph resolves, but two builds of the same commit can pull different transitive versions if an upstream artifact republishes or a version range widens.
Version ranges. Scala projects tend to pin exact versions in libraryDependencies, which makes lockfiles less pressing than in ecosystems that default to ranges. With exact pins throughout and warm caches, resolution is effectively deterministic even without a lockfile plugin.