23.4 The Manifest: Cargo.toml
The Cargo.toml
file is the heart of a Rust package (crate). It uses the TOML (Tom’s Obvious, Minimal Language) format to define metadata and dependencies.
23.4.1 Common Sections
A typical Cargo.toml
includes several sections:
[package]
name = "my_crate"
version = "0.1.0"
edition = "2021" # Specifies the Rust edition (e.g., 2015, 2018, 2021)
authors = ["Your Name <you@example.com>"]
description = "A short description of what my_crate does."
license = "MIT OR Apache-2.0" # SPDX license expression
repository = "[https://github.com/your_username/my_crate](https://github.com/your_username/my_crate)" # Optional: URL to source repo
readme = "README.md" # Optional: Path to README file
keywords = ["cli", "utility"] # Optional: Keywords for Crates.io search
[dependencies]
# Lists crates needed to compile and run the main code
serde = { version = "1.0", features = ["derive"] } # Example with version and features
rand = "0.8"
log = "0.4"
[dev-dependencies]
# Lists crates needed only for tests, examples, and benchmarks
assert_cmd = "2.0"
criterion = "0.4"
[build-dependencies]
# Lists crates needed by build scripts (build.rs)
# Example: cc = "1.0"
[features]
# Defines optional features for conditional compilation
default = ["std_feature"] # Default features enabled if none specified
std_feature = []
serde_support = ["dep:serde"] # Feature enabling an optional dependency
[profile.release]
# Customizes the 'release' build profile (e.g., for optimizations)
opt-level = 3 # Optimization level (0-3, 's', 'z')
lto = true # Enable Link-Time Optimization
codegen-units = 1 # Fewer codegen units for potentially better optimization
# See also: [profile.dev], [profile.test], [profile.bench]
[package]
: Core metadata about the crate. Fields likename
,version
,edition
,description
, andlicense
are essential, especially if publishing to Crates.io.[dependencies]
: Lists the crates your package depends on to run. Cargo downloads these from Crates.io by default.[dev-dependencies]
: Crates needed only for development tasks like running tests, benchmarks, or examples. They are not included when someone uses your crate as a dependency.[build-dependencies]
: Crates required by abuild.rs
script (a script Cargo runs before compiling your crate, often used for code generation or compiling C code).[features]
: Allows defining optional features that enable conditional compilation, often used to toggle functionality or optional dependencies.[profile.*]
: Sections for customizing build profiles (dev
,release
,test
,bench
). (See Section 23.6).
23.4.2 Specifying Dependencies
Dependencies are listed under the [dependencies]
(or [dev-dependencies]
, [build-dependencies]
) section. The simplest form specifies the crate name and a version requirement:
[dependencies]
regex = "1.5"
Cargo uses Semantic Versioning (SemVer). The version string "1.5"
is shorthand for "^1.5.0"
, meaning Cargo will accept any version v
where 1.5.0 <= v < 2.0.0
. This allows compatible minor and patch updates automatically. Other common specifiers include:
"~1.5.2"
: Allows only patch updates (>= 1.5.2, < 1.6.0
)."=1.5.2"
: Requires exactly version1.5.2
.">=1.5.0, <1.6.0"
: Specifies an explicit range."*"
: Accepts any version (use with caution).
You can also specify dependencies from other sources:
[dependencies]
# From a Git repository
some_lib = { git = "[https://github.com/user/some_lib.git](https://github.com/user/some_lib.git)", branch = "main" }
# From a local path (useful during development or in workspaces)
local_util = { path = "../local_util" }
# With optional features enabled
serde = { version = "1.0", features = ["derive"] }
# Marked as optional (only included if a feature enables it)
# In [dependencies]:
# mio = { version = "0.8", optional = true }
# In [features]:
# network = ["dep:mio"]
23.4.3 The Cargo.lock
File
When you build your project for the first time, or after modifying dependencies in Cargo.toml
, Cargo resolves all dependencies (including transitive ones) and records the exact versions used in the Cargo.lock
file.
- Purpose: Ensures reproducible builds. Anyone building the project with the same
Cargo.lock
file will use the exact same dependency versions, preventing unexpected changes due to automatic updates. - Management:
Cargo.lock
is automatically generated and updated by Cargo commands likebuild
,check
,add
,remove
, orupdate
. You should not edit it manually. - Version Control:
- For binary applications: Always commit
Cargo.lock
to version control. This guarantees that every developer, CI system, and deployment uses the same dependency set. - For libraries: Committing
Cargo.lock
is optional and debated.- Pro-Commit: Ensures the library’s own tests run with a consistent set of dependencies in CI.
- Anti-Commit: Libraries are typically used as dependencies themselves. The downstream application’s
Cargo.lock
will ultimately determine the versions used. Committing the library’sCargo.lock
doesn’t affect consumers and might cause merge conflicts. Many library authors choose not to commitCargo.lock
.
- For binary applications: Always commit
23.4.4 Updating Dependencies
cargo update
: ReadsCargo.toml
and updates dependencies listed inCargo.lock
to the latest compatible versions allowed by the version specifications inCargo.toml
. It does not changeCargo.toml
itself.cargo update -p <crate_name>
: Updates only a specific dependency and its dependents.
- Upgrading Dependencies (Major Versions): To use a new major version (e.g., moving from
serde
“1.0” to “2.0”), you must manually edit the version requirement inCargo.toml
. Tools likecargo-edit
(cargo upgrade
) can assist with this. - Checking for Outdated Dependencies: Use
cargo outdated
(from thecargo-outdated
tool) to see which dependencies have newer versions available than what’s currently inCargo.lock
.