Rust Crates
A crate is a single unit of code that Rust compiles. A package is the Cargo project that holds one library crate, one or more binary crates, and a Cargo.toml file.
A package holds crates
Package: what cargo new creates — a Cargo.toml plus source code. Crate: one compiled unit inside it. A package holds at most one library crate. It holds as many binary crates as you like. It holds at least one crate in total:
// my_project/ <- the package
// Cargo.toml
// src/main.rs <- one binary crate
// src/lib.rs <- the one library crate (optional)Add a library under [dependencies]
Name the crate you want, and the versions you accept. Features let you turn on only the parts of a library you need:
// in Cargo.toml:
[dependencies]
serde = { version = "1", features = ["derive"] }A library shares code; a binary runs
A binary crate runs and must have a fn main. A library crate has no main — it shares code for other projects to use, like rand. A package can hold both together. Keep the binary thin. Let it call the library. Then other projects can reuse the same code:
// src/lib.rs — the library crate
pub fn add(a: i32, b: i32) -> i32 { a + b }
// src/main.rs — the binary crate
fn main() {
println!("sum = {}", my_project::add(2, 3));
}Extra programs live in src/bin/
Each file there becomes its own binary crate, in the same package:
// src/bin/report.rs -> its own binary crate: cargo run --bin report
// src/bin/fixup.rs -> another one: cargo run --bin fixupOne file on its own is a crate too
A crate is the smallest unit the compiler works on. Even one single file handed straight to rustc counts as one crate:
// hello.rs, compiled on its own with: rustc hello.rs
fn main() {
println!("one file, one crate");
}Example
// Cargo.toml
// [dependencies]
// rand = "0.8"
// src/main.rs conceptually:
fn main() {
let deps = ["serde", "tokio", "clap"];
println!("{} popular crates, {} file pins versions", deps.len(), "Cargo.lock");
for d in deps { println!("- {}", d); }
}Key points
- Cargo.lock records the exact versions chosen — save it in version control for programs
- Use cargo tree to see which libraries your project is using, and why
- Cargo commands work from any folder inside the project.
- Cargo searches upward for Cargo.toml.
- It rebuilds only the parts that changed since the last build.
- The lockfile is what makes "it worked yesterday" reproducible today.
- Crates from other people live on crates.io.
In this example, there is no real library to call, so the code demonstrates the idea with plain data. deps lists three famous crates: serde (data formats), tokio (async), and clap (command-line parsing). The program prints how many there are — 3 — and notes that Cargo.lock is the file pinning exact versions. Then it prints each name on its own line. In a real project, naming these crates under [dependencies] is all it takes to use them.
Note
Versions follow semver: "1.2" allows updates that promise not to break your code.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What is the difference between a package and a crate?