Cargo is the standard build toolchain for Rust.

Every release of rustc is shipped with a specific version of cargo.

In general, cargo is independent of the used rustc version.


A cargo project contains (at minimum):

  • A Manifest (Cargo.toml)

  • A source file (library or application) in the src folder (default)

In addition, a cargo project can contain:

  • tests (default directory tests)

  • benchmarks (default directory benches)

  • a build script (default

  • examples (default directory examples)

The Manifest

The Cargo Manifest is written using TOML.

It at least contains the name of the project.

name = "tcp-mailbox"
version = "0.1.0"
authors = ["Florian Gilcher <>"]

async-std = "1" # would also choose 1.5
clap = "2.2" # would also choose 2.3

cargo build

cargo build builds the whole project and puts the result in the directory target.

By default, cargo uses the Debug profile, which means that the resulting binary with be unoptimized and with debug symbols!

cargo build --release uses the optimizing profile.

Always use --release for benchmarks, especially iterators get a huge speed boost from optimizations.

cargo run

If the project contains an application, you can run it using cargo run -- [Arguments].

If it contains multiple binaries, the name of the intended binary can be given using --bin <name>.

The debug profile is default here.

cargo test

cargo test runs all tests.

You can provide a test name or module name to filter the test being run.

Tests use the debug profile per default.

cargo test --workspace --examples runs all tests, including documentation test and compilation of examples!

cargo bench

cargo bench runs all benchmarks.

Benchmarks default to the release profile.

Benchmarks can be written using the criterion crate.


In the Rust community Semantic Versioning is the recommended versioning standard.

  • The major version must be raised if there are breaking interface changes.

  • The minor version must be raised if new features are added

  • The patch version marks bug fixes and performance improvements.


If the version of a library is below 1, it is considered "pre-release", which means breaking interface changes can happen with every minor version, and in the 0.0.x case, with every patch version.

Version expressions

Cargo allows expressing version ranges in different fashions.

  • =1.2.3: Exact version, cargo will only use that one

  • 0.1: Any patch version of the "0.1" series

  • 1.0: Any minor version of the "1.x" series

  • < 0.8: Any minor version smaller than "0.8"

For more details, check the docs

Version resolution

At the first build (or through cargo update), cargo calculates a version tree fulfilling the constraints stated in Cargo.toml.

If successful, it will be saved in a Lockfile (Cargo.lock).

The Lockfile should always be kept under version control for applications.

For libraries, it can be checked in to provide a repeatable test environment.

Dependencies in detail

Cargo knows 3 different kinds of dependencies:

  • normal dependencies

  • build dependencies

  • development/test dependencies


async-std = "1"

cbindgen = "0.5"

quickcheck = "0.9"

Dependencies in detail

version = "1"
git = ""
branch = "my-new-feature"
version = "1"
path = "/my/local/path"


Dependencies outside of are forbidden if a library is to be published on

Local paths

It is possible to temporarily replace libraries with local ones.

For this, their path needs to be registered in $PROJECT_PATH/.cargo/config.

paths = ["/my/local/path", "/another/path"]

Libraries found here will be preferred. This allows easy testing of patches.


The cargo profiles (release, bench, test…​) can be customized.

Details can be found in the Manifest-documentation.


  • profiles and dependencies can be configured based on the compilation target

  • cargo build --target ... uses that target

  • the target must be installed beforehand

  • consider using xargo


Cargo can group multiple projects in a workspace.

They then share settings and the same target directory.

See the manifest documentation for details.


rustc provides the ability to ignore certain code parts on compilation.

This happens through feature flags.

fn amazing_function() {


These can be registered in Cargo.toml.

default = []
# Turns on experimental features.
experimental = []

And then be expressed on a dependency:

version = "0.1"
features = ["experimental"]

or used with +cargo build --features experimental,other_feature

Directly invoking rustc

cargo rustc invokes rustc directly and allows passing of additional parameters.