23.4 Cargo.toml

The Cargo.toml file serves as the manifest for each package. Written in the TOML format, it includes metadata required for compiling the package.

23.4.1 Structure

Cargo.toml is a file describing your package:

[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <you@example.com>"]
description = "A brief description of your crate"
license = "MIT OR Apache-2.0"
repository = "https://github.com/yourname/my_project"

[dependencies]
serde = "1.0"
rand = "0.8"

[dev-dependencies]
quickcheck = "1.0"

[features]
# Optional features can be declared here.

[profile.dev]
# Customize debug builds here.

[profile.release]
# Customize release builds here.
  • [package]: Defines package metadata (name, version, edition, license, etc.).
  • [dependencies]: Lists runtime dependencies (usually from Crates.io).
  • [dev-dependencies]: Dependencies for tests, benchmarks, or development tools.
  • [profile.*]: Customizes debug and release builds.

If you plan to publish on Crates.io, ensure [package] includes all required metadata (e.g., license, description, version).

23.4.2 Managing Dependencies

Cargo automatically resolves and fetches dependencies. You declare them in Cargo.toml; Cargo handles downloading and building them.

Adding Dependencies Manually

Add a dependency with a name and version (using Semantic Versioning):

[dependencies]
serde = "1.0"

Cargo fetches the crate from Crates.io if it’s not already downloaded.

Semantic Versioning (SemVer) in Cargo

  • "1.2.3" or "^1.2.3": Accepts bugfix and minor updates in 1.x (>=1.2.3, <2.0.0).
  • "~1.2.3": Restricts updates to the same minor version (>=1.2.3, <1.3.0).
  • "=1.2.3": Requires exactly 1.2.3.
  • ">=1.2.3, <1.5.0": Uses a version range.

Updating vs. Upgrading

  • Update: cargo update pulls the latest compatible versions based on current constraints (updating only Cargo.lock).
  • Upgrade: Loosens constraints or bumps major versions in Cargo.toml, then runs cargo update. This changes both Cargo.toml and Cargo.lock.

Cargo.lock

  • Cargo.lock records exact version information (including transitive dependencies).
  • Commit Cargo.lock for applications/binaries so everyone builds the same versions.
  • For library crates, maintaining Cargo.lock is optional. Library consumers usually manage their own lock files. Some library authors still commit it for continuous integration (CI) reproducibility.

Checking for Outdated Dependencies

Install and run cargo-outdated to see out-of-date crates:

cargo install cargo-outdated
cargo outdated

This is helpful for planning version upgrades.

Alternative Sources and Features

You can fetch crates from Git repositories or local paths:

[dependencies]
my_crate = { git = "https://github.com/user/my_crate" }

Enable optional features in a dependency:

[dependencies]
serde = { version = "1.0", features = ["derive"] }

This activates additional functionality, such as automatically deriving Serialize and Deserialize.