Dependencies in lib go on all the classpaths (for compile, test, run,
and console). If you wanted to change the classpath for just one of
those, you would adjust dependencyClasspath in Compile or
dependencyClasspath in Runtime for example.

There’s nothing to add to build.sbt to use unmanaged dependencies,
though you could change the unmanagedBase key if you’d like to use a
different directory rather than lib.

To use custom_lib instead of lib:

unmanagedBase := baseDirectory.value / "custom_lib"

baseDirectory is the project’s root directory, so here you’re changing
unmanagedBase depending on baseDirectory using the special value method
as explained in task graph.

There’s also an unmanagedJars task which lists the jars from the
unmanagedBase directory. If you wanted to use multiple directories or do
something else complex, you might need to replace the whole
unmanagedJars task with one that does something else, e.g. empty the list for
Compile configuration regardless of the files in lib directory:

Compile / unmanagedJars := Seq.empty[sbt.Attributed[java.io.File]]

Managed Dependencies

sbt uses Apache Ivy to implement managed
dependencies, so if you’re familiar with Ivy or Maven, you won’t have
much trouble.

The libraryDependencies key

Most of the time, you can simply list your dependencies in the setting
libraryDependencies. It’s also possible to write a Maven POM file or Ivy
configuration file to externally configure your dependencies, and have
sbt use those external configuration files. You can learn more about
that here.

Declaring a dependency looks like this, where groupId, artifactId, and
revision are strings:

libraryDependencies += groupID % artifactID % revision

or like this, where configuration can be a string or
Configuration val:

The % methods create ModuleID objects from strings, then you add those
ModuleID to libraryDependencies.

Of course, sbt (via Ivy) has to know where to download the module. If
your module is in one of the default repositories sbt comes with, this
will just work. For example, Apache Derby is in the standard Maven2
repository:

libraryDependencies += "org.apache.derby" % "derby" % "10.4.1.3"

If you type that in build.sbt and then update, sbt should download Derby
to ~/.ivy2/cache/org.apache.derby/. (By the way, update is a dependency
of compile so there’s no need to manually type update most of the time.)

Of course, you can also use ++= to add a list of dependencies all at
once:

In rare cases you might find reasons to use := with libraryDependencies
as well.

Getting the right Scala version with %%

If you use groupID %% artifactID % revision rather than
groupID % artifactID % revision (the difference is the double %% after
the groupID), sbt will add your project’s binary Scala version to the artifact
name. This is just a shortcut. You could write this without the %%:

libraryDependencies += "org.scala-tools" % "scala-stm_2.11" % "0.3"

Assuming the scalaVersion for your build is 2.11.1, the following is
identical (note the double %% after "org.scala-tools"):

libraryDependencies += "org.scala-tools" %% "scala-stm" % "0.3"

The idea is that many dependencies are compiled for multiple Scala
versions, and you’d like to get the one that matches your project
to ensure binary compatibility.

Ivy revisions

The revision in groupID % artifactID % revision does not have to be a
single fixed version. Ivy can select the latest revision of a module
according to constraints you specify. Instead of a fixed revision like
"1.6.1", you specify "latest.integration", "2.9.+", or "[1.0,)". See the
Ivy
revisions
documentation for details.

Resolvers

Not all packages live on the same server; sbt uses the standard Maven2
repository by default. If your dependency isn’t on one of the default
repositories, you’ll have to add a resolver to help Ivy find it.

Now, if you type show compile:dependencyClasspath at the sbt interactive
prompt, you should not see the derby jar. But if you type
show test:dependencyClasspath, you should see the derby jar in the list.