A crate is a compilation unit in Rust. This means, if a crate depends on other crates, the dependencies don't need to be recompiled when the root crate changes. However, it's not possible to compile only a part of a crate.
Crates can be published on Crates.io, which makes it easier for other crates to depend on them.
A crate can depend on other crates, which in turn can depend on other crates, which results in a dependency graph. It is sometimes incorrectly called a tree, although a crate can be depended on by multiple crates in a dependency graph. However, cyclic dependencies are not allowed. For example, if crate A depends on crate B, then B cannot depend on A.
Crates have a version, which should follow the SemVer specification. As a summary, a version consists of three numbers, e.g.
3.1.5. The three numbers are called MAJOR, MINOR and PATCH. Two versions are considered compatible, if the first number in the version that isn't
0 is the same in both versions, so
0.5.6 are compatible, but
0.6.0 are not.
If a crate is used by more than one of your dependencies, Cargo tries to find a version of the crate that is compatible with all version requirements. If more than one applicable version is found, the newest one is used. If no version is compatible with all dependent crates, then multiple versions of the same crate are used. This is important, since it can have unexpected consequences:
- Global state of the dependency exists multiple times
- An exported type is not compatible with the same type from a different version; Rust treats them as different types that just happen to have the same name
- The compiled binary can be bigger than expected
Main article: Editions
A crate can use the 2015 edition or the 2018 edition. Although the 2018 edition is recommended, the 2015 edition is the default for backwards compatibility. Since newer compilers can handle both editions, crates from different editions can be mixed and matched: A crate with the 2015 edition can depend on crates in the 2018 edition and vice versa.
See also: Features – The Cargo Book
A crate can specify features that can be enabled and disabled. Features are additive, so enabling a feature should never remove functionality. For example, it's common to have a feature called
std, which enables features that depend on the standard library. If a crate has a
no_std feature that disables certain features, this is wrong and can cause serious problems.
See also: Targets – The Cargo Book
There are five kinds of targets: Library, binary, example, test and benchmark targets. A crate can only have one library targets, all other targets can be used multiple times.
See also: Build scripts – The Cargo Book
A crate can specify a build script, which is a Rust file called
build.rs. The build script is run every time the crate is compiled. It can have dependencies, which are specified in the
Main article: Procedural macros
A crate can specify that it is a proc-macro crate, which means that it exports procedural macros (and nothing else). Procedural macros must live in their own crate, because they are compiled before everything else.