Specifying Dependencies
Your crates can depend on other libraries fromcrates.io or otherregistries,git repositories, or subdirectories on your local file system.You can also temporarily override the location of a dependency — for example,to be able to test out a bug fix in the dependency that you are working onlocally. You can have different dependencies for different platforms, anddependencies that are only used during development. Let’s take a look at howto do each of these.
Specifying dependencies from crates.io
Cargo is configured to look for dependencies oncrates.io by default. Onlythe name and a version string are required in this case. Inthe cargoguide, we specified a dependency on thetime crate:
[dependencies]time = "0.1.12"The version string"0.1.12" is called aversion requirement.It specifies a range of versions that can be selected from whenresolving dependencies.In this case,"0.1.12" represents the version range>=0.1.12, <0.2.0.An update is allowed if it is within that range.In this case, if we rancargo update time, cargo shouldupdate us to version0.1.13 if it is the latest0.1.z release, but would notupdate us to0.2.0.
Version requirement syntax
Default requirements
Default requirements specify a minimum version with the ability to update toSemVer compatible versions.Versions are considered compatible if their left-most non-zero major/minor/patch component is the same.This is different fromSemVer which considers all pre-1.0.0 packages to be incompatible.
1.2.3 is an example of a default requirement.
1.2.3 := >=1.2.3, <2.0.01.2 := >=1.2.0, <2.0.01 := >=1.0.0, <2.0.00.2.3 := >=0.2.3, <0.3.00.2 := >=0.2.0, <0.3.00.0.3 := >=0.0.3, <0.0.40.0 := >=0.0.0, <0.1.00 := >=0.0.0, <1.0.0Caret requirements
Caret requirements are the default version requirement strategy.This version strategy allowsSemVer compatible updates.They are specified as version requirements with a leading caret (^).
^1.2.3 is an example of a caret requirement.
Leaving off the caret is a simplified equivalent syntax to using caret requirements.While caret requirements are the default, it is recommended to use thesimplified syntax when possible.
log = "^1.2.3" is exactly equivalent tolog = "1.2.3".
Tilde requirements
Tilde requirements specify a minimal version with some ability to update.If you specify a major, minor, and patch version or only a major and minorversion, only patch-level changes are allowed. If you only specify a majorversion, then minor- and patch-level changes are allowed.
~1.2.3 is an example of a tilde requirement.
~1.2.3 := >=1.2.3, <1.3.0~1.2 := >=1.2.0, <1.3.0~1 := >=1.0.0, <2.0.0Wildcard requirements
Wildcard requirements allow for any version where the wildcard ispositioned.
*,1.* and1.2.* are examples of wildcard requirements.
* := >=0.0.01.* := >=1.0.0, <2.0.01.2.* := >=1.2.0, <1.3.0Note:crates.io does not allow bare
*versions.
Comparison requirements
Comparison requirements allow manually specifying a version range or anexact version to depend on.
Here are some examples of comparison requirements:
>= 1.2.0> 1< 2= 1.2.3Multiple version requirements
As shown in the examples above, multiple version requirements can beseparated with a comma, e.g.,>= 1.2, < 1.5.
Pre-releases
Version requirements excludepre-release versions, such as1.0.0-alpha,unless specifically asked for.For example, if1.0.0-alpha of packagefoo is published, then a requirement offoo = "1.0" willnot match, andwill return an error. The pre-release must be specified, such asfoo = "1.0.0-alpha".Similarlycargo install will avoid pre-releases unlessexplicitly asked to install one.
Cargo allows “newer” pre-releases to be used automatically. For example, if1.0.0-beta is published, then a requirementfoo = "1.0.0-alpha" will allowupdating to thebeta version. Note that this only works on the same releaseversion,foo = "1.0.0-alpha" will not allow updating tofoo = "1.0.1-alpha"orfoo = "1.0.1-beta".
Cargo will also upgrade automatically to semver-compatible released versionsfrom prereleases. The requirementfoo = "1.0.0-alpha" will allow updating tofoo = "1.0.0" as well asfoo = "1.2.0".
Beware that pre-release versions can be unstable, and as such care should betaken when using them. Some projects may choose to publish breaking changesbetween pre-release versions. It is recommended to not use pre-releasedependencies in a library if your library is not also a pre-release. Careshould also be taken when updating yourCargo.lock, and be prepared if apre-release update causes issues.
Version metadata
Version metadata, such as1.0.0+21AF26D3,is ignored and should not be used in version requirements.
Recommendation: When in doubt, use the default version requirement operator.
In rare circumstances, a package with a “public dependency”(re-exports the dependency or interoperates with it in its public API)that is compatible with multiple semver-incompatible versions(e.g. only uses a simple type that hasn’t changed between releases, like an
Id)may support users choosing which version of the “public dependency” to use.In this case, a version requirement like">=0.4, <2"may be of interest.However users of the package will likely run into errors and need tomanually select a version of the “public dependency” viacargo updateifthey also depend on it as Cargo might pick different versions of the “publicdependency” whenresolving dependency versions (see#10599).Avoid constraining the upper bound of a version to be anything less than thenext semver incompatible version(e.g. avoid
">=2.0, <2.4","2.0.*", or~2.0),as other packages in the dependency tree mayrequire a newer version, leading to an unresolvable error (see#9029).Consider whether controlling the version in yourCargo.lockwould be moreappropriate.In some instances this won’t matter or the benefits might outweigh the cost, including:
- When no one else depends on your package; e.g. it only has a
[[bin]]- When depending on a pre-release package and wishing to avoid breakingchanges, then a fully specified
"=1.2.3-alpha.3"might be warranted (see#2222)- When a library re-exports a proc-macro but the proc-macro generates code thatcalls into the re-exporting library, then a fully specified
=1.2.3might bewarranted to ensure the proc-macro isn’t newer than the re-exporting libraryand generating code that uses parts of the API that don’t exist within thecurrent version
Specifying dependencies from other registries
To specify a dependency from a registry other thancrates.io set theregistry keyto the name of the registry to use:
[dependencies]some-crate = { version = "1.0", registry = "my-registry" }wheremy-registry is the registry name configured in.cargo/config.toml file.See theregistries documentation for more information.
Note:crates.io does not allow packages to be published withdependencies on code published outside ofcrates.io.
Specifying dependencies fromgit repositories
To depend on a library located in agit repository, the minimum informationyou need to specify is the location of the repository with thegit key:
[dependencies]regex = { git = "https://github.com/rust-lang/regex.git" }Cargo fetches thegit repository at that location and traverses the file tree to findCargo.toml file for the requested crate anywhere inside thegit repository.For example,regex-lite andregex-syntax are members ofrust-lang/regex repoand can be referred to by the repo’s root URL (https://github.com/rust-lang/regex.git)regardless of where in the file tree they reside.
regex-lite = { git = "https://github.com/rust-lang/regex.git" }regex-syntax = { git = "https://github.com/rust-lang/regex.git" }The above rule does not apply topath dependencies.
Choice of commit
Cargo assumes that we intend to use the latest commit on the default branch to buildour package if we only specify the repo URL, as in the examples above.
You can combine thegit key with therev,tag, orbranch keys to be more specific aboutwhich commit to use. Here’s an example of using the latest commit on a branch namednext:
[dependencies]regex = { git = "https://github.com/rust-lang/regex.git", branch = "next" }Anything that is not a branch or a tag falls underrev key. This can be a commithash likerev = "4c59b707", or a named reference exposed by the remoterepository such asrev = "refs/pull/493/head".
What references are available for therev key varies by where the repo is hosted.
GitHub exposes a reference to the most recent commit of every pull request as in the example above.Other git hosts may provide something equivalent under a different naming scheme.
Moregit dependency examples:
# .git suffix can be omitted if the host accepts such URLs - both examples work the sameregex = { git = "https://github.com/rust-lang/regex" }regex = { git = "https://github.com/rust-lang/regex.git" }# a commit with a particular tagregex = { git = "https://github.com/rust-lang/regex.git", tag = "1.10.3" }# a commit by its SHA1 hashregex = { git = "https://github.com/rust-lang/regex.git", rev = "0c0990399270277832fbb5b91a1fa118e6f63dba" }# HEAD commit of PR 493regex = { git = "https://github.com/rust-lang/regex.git", rev = "refs/pull/493/head" }# INVALID EXAMPLES# specifying the commit after # ignores the commit ID and generates a warningregex = { git = "https://github.com/rust-lang/regex.git#4c59b70" }# git and path cannot be used at the same timeregex = { git = "https://github.com/rust-lang/regex.git#4c59b70", path = "../regex" }Cargo locks the commits ofgit dependencies inCargo.lock file at the time of their additionand checks for updates only when you runcargo update command.
The role of theversion key
Theversion key always implies that the package is available in a registry,regardless of the presence ofgit orpath keys.
Theversion key doesnot affect which commit is used when Cargo retrieves thegit dependency,but Cargo checks the version information in the dependency’sCargo.toml fileagainst theversion key and raises an error if the check fails.
In this example, Cargo retrieves the HEAD commit of the branch callednext from Git and checks if the crate’s versionis compatible withversion = "1.10.3":
[dependencies]regex = { version = "1.10.3", git = "https://github.com/rust-lang/regex.git", branch = "next" }version,git, andpath keys are considered separate locations for resolving the dependency.SeeMultiple locations section below for detailed explanations.
Note:crates.io does not allow packages to be published withdependencies on code published outside ofcrates.io itself(dev-dependencies are ignored). See theMultiplelocations section for a fallback alternative for
gitandpathdependencies.
Git submodules
When cloning agit dependency,Cargo automatically fetches its submodules recursivelyso that all required code is available for the build.
To skip fetching submodules unrelated to the build,you can setsubmodule.<name>.update = none in the dependency repo’s.gitmodules.This requires write access to the repo and will disable submodule updates more generally.
Accessing private Git repositories
SeeGit Authentication for help with Git authentication for private repos.
Specifying path dependencies
Over time, ourhello_world package fromthe guide hasgrown significantly in size! It’s gotten to the point that we probably want tosplit out a separate crate for others to use. To do this Cargo supportspathdependencies which are typically sub-crates that live within one repository.Let’s start by making a new crate inside of ourhello_world package:
# inside of hello_world/$ cargo new hello_utilsThis will create a new folderhello_utils inside of which aCargo.toml andsrc folder are ready to be configured. To tell Cargo about this, openuphello_world/Cargo.toml and addhello_utils to your dependencies:
[dependencies]hello_utils = { path = "hello_utils" }This tells Cargo that we depend on a crate calledhello_utils which is foundin thehello_utils folder, relative to theCargo.toml file it’s written in.
The nextcargo build will automatically buildhello_utils andall of its dependencies.
No local path traversal
The local paths must point to the exact folder with the dependency’sCargo.toml.Unlike withgit dependencies, Cargo does not traverse local paths.For example, ifregex-lite andregex-syntax are members of alocally clonedrust-lang/regex repo, they have to be referred to by the full path:
# git key accepts the repo root URL and Cargo traverses the tree to find the crate[dependencies]regex-lite = { git = "https://github.com/rust-lang/regex.git" }regex-syntax = { git = "https://github.com/rust-lang/regex.git" }# path key requires the member name to be included in the local path[dependencies]regex-lite = { path = "../regex/regex-lite" }regex-syntax = { path = "../regex/regex-syntax" }Local paths in published crates
Crates that use dependencies specified with only a path are notpermitted oncrates.io.
If we wanted to publish ourhello_world crate,we would need to publish a version ofhello_utils tocrates.io as a separate crateand specify its version in the dependencies line ofhello_world:
[dependencies]hello_utils = { path = "hello_utils", version = "0.1.0" }The use ofpath andversion keys together is explained in theMultiple locations section.
Note:crates.io does not allow packages to be published withdependencies on code outside ofcrates.io, except fordev-dependencies.See theMultiple locations sectionfor a fallback alternative for
gitandpathdependencies.
Multiple locations
It is possible to specify both a registry version and agit orpathlocation. Thegit orpath dependency will be used locally (in which casetheversion is checked against the local copy), and when published to aregistry likecrates.io, it will use the registry version. Othercombinations are not allowed. Examples:
[dependencies]# Uses `my-bitflags` when used locally, and uses# version 1.0 from crates.io when published.bitflags = { path = "my-bitflags", version = "1.0" }# Uses the given git repo when used locally, and uses# version 1.0 from crates.io when published.smallvec = { git = "https://github.com/servo/rust-smallvec.git", version = "1.0" }# Note: if a version doesn't match, Cargo will fail to compile!One example where this can be useful is when you have split up a library intomultiple packages within the same workspace. You can then usepathdependencies to point to the local packages within the workspace to use thelocal version during development, and then use thecrates.io version once itis published. This is similar to specifying anoverride, but only applies to this onedependency declaration.
Platform specific dependencies
Platform-specific dependencies take the same format, but are listed under atarget section. Normally Rust-like#[cfg]syntax will be used to definethese sections:
[target.'cfg(windows)'.dependencies]winhttp = "0.4.0"[target.'cfg(unix)'.dependencies]openssl = "1.0.1"[target.'cfg(target_arch = "x86")'.dependencies]native-i686 = { path = "native/i686" }[target.'cfg(target_arch = "x86_64")'.dependencies]native-x86_64 = { path = "native/x86_64" }Like with Rust, the syntax here supports thenot,any, andall operatorsto combine various cfg name/value pairs.
If you want to know which cfg targets are available on your platform, runrustc --print=cfg from the command line. If you want to know whichcfgtargets are available for another platform, such as 64-bit Windows,runrustc --print=cfg --target=x86_64-pc-windows-msvc.
Unlike in your Rust source code, you cannot use[target.'cfg(feature = "fancy-feature")'.dependencies] to add dependenciesbased on optional features. Usethe[features] sectioninstead:
[dependencies]foo = { version = "1.0", optional = true }bar = { version = "1.0", optional = true }[features]fancy-feature = ["foo", "bar"]The same applies tocfg(debug_assertions),cfg(test) andcfg(proc_macro).These values will not work as expected and will always have the default valuereturned byrustc --print=cfg.There is currently no way to add dependencies based on these configuration values.
In addition to#[cfg] syntax, Cargo also supports listing out the full targetthe dependencies would apply to:
[target.x86_64-pc-windows-gnu.dependencies]winhttp = "0.4.0"[target.i686-unknown-linux-gnu.dependencies]openssl = "1.0.1"Custom target specifications
If you’re using a custom target specification (such as--target foo/bar.json), use the base filename without the.json extension:
[target.bar.dependencies]winhttp = "0.4.0"[target.my-special-i686-platform.dependencies]openssl = "1.0.1"native = { path = "native/i686" }Note: Custom target specifications are not usable on the stable channel.
Development dependencies
You can add a[dev-dependencies] section to yourCargo.toml whose formatis equivalent to[dependencies]:
[dev-dependencies]tempdir = "0.3"Dev-dependencies are not used when compilinga package for building, but are used for compiling tests, examples, andbenchmarks.
These dependencies arenot propagated to other packages which depend on thispackage.
You can also have target-specific development dependencies by usingdev-dependencies in the target section header instead ofdependencies. Forexample:
[target.'cfg(unix)'.dev-dependencies]mio = "0.0.1"Note: When a package is published, only dev-dependencies that specify a
versionwill be included in the published crate. For most use cases,dev-dependencies are not needed when published, though some users (like OSpackagers) may want to run tests within a crate, so providing aversionifpossible can still be beneficial.
Build dependencies
You can depend on other Cargo-based crates for use in your build scripts.Dependencies are declared through thebuild-dependencies section of themanifest:
[build-dependencies]cc = "1.0.3"You can also have target-specific build dependencies by usingbuild-dependencies in the target section header instead ofdependencies. Forexample:
[target.'cfg(unix)'.build-dependencies]cc = "1.0.3"In this case, the dependency will only be built when the host platform matches thespecified target.
The build scriptdoes not have access to the dependencies listedin thedependencies ordev-dependencies section. Builddependencies will likewise not be available to the package itselfunless listed under thedependencies section as well. A packageitself and its build script are built separately, so theirdependencies need not coincide. Cargo is kept simpler and cleaner byusing independent dependencies for independent purposes.
Choosing features
If a package you depend on offers conditional features, you canspecify which to use:
[dependencies.awesome]version = "1.3.5"default-features = false # do not include the default features, and optionally # cherry-pick individual featuresfeatures = ["secure-password", "civet"]More information about features can be found in thefeatureschapter.
Renaming dependencies inCargo.toml
When writing a[dependencies] section inCargo.toml the key you write for adependency typically matches up to the name of the crate you import from in thecode. For some projects, though, you may wish to reference the crate with adifferent name in the code regardless of how it’s published on crates.io. Forexample you may wish to:
- Avoid the need to
use foo as barin Rust source. - Depend on multiple versions of a crate.
- Depend on crates with the same name from different registries.
To support this Cargo supports apackage key in the[dependencies] sectionof which package should be depended on:
[package]name = "mypackage"version = "0.0.1"[dependencies]foo = "0.1"bar = { git = "https://github.com/example/project.git", package = "foo" }baz = { version = "0.1", registry = "custom", package = "foo" }In this example, three crates are now available in your Rust code:
extern crate foo; // crates.ioextern crate bar; // git repositoryextern crate baz; // registry `custom`All three of these crates have the package name offoo in their ownCargo.toml, so we’re explicitly using thepackage key to inform Cargo thatwe want thefoo package even though we’re calling it something else locally.Thepackage key, if not specified, defaults to the name of the dependencybeing requested.
Note that if you have an optional dependency like:
[dependencies]bar = { version = "0.1", package = 'foo', optional = true }you’re depending on the cratefoo from crates.io, but your crate has abarfeature instead of afoo feature. That is, names of features take after thename of the dependency, not the package name, when renamed.
Enabling transitive dependencies works similarly, for example we could add thefollowing to the above manifest:
[features]log-debug = ['bar/log-debug'] # using 'foo/log-debug' would be an error!Inheriting a dependency from a workspace
Dependencies can be inherited from a workspace by specifying thedependency in the workspace’s[workspace.dependencies] table.After that, add it to the[dependencies] table withworkspace = true.
Along with theworkspace key, dependencies can also include these keys:
optional: Note that the[workspace.dependencies]table is not allowed to specifyoptional.features: These are additive with the features declared in the[workspace.dependencies]
Other thanoptional andfeatures, inherited dependencies cannot use any otherdependency key (such asversion ordefault-features).
Dependencies in the[dependencies],[dev-dependencies],[build-dependencies], and[target."...".dependencies] sections support the ability to reference the[workspace.dependencies] definition of dependencies.
[package]name = "bar"version = "0.2.0"[dependencies]regex = { workspace = true, features = ["unicode"] }[build-dependencies]cc.workspace = true[dev-dependencies]rand = { workspace = true, optional = true }