Rust Build ConfigurationCargoDependenciesRust

Article & Tutorial

Cargo Dependencies, Features, Versions and Build Configuration: Complete Guide

Master Cargo.toml, dependency versions, Cargo.lock, feature flags, optional dependencies, build profiles and workspace dependencies in Rust.

Cargo Dependencies, Features, Versions and Build Configuration: Complete Guide article illustration
Cargo Dependencies, Features, Versions and Build Configuration: Complete Guide article illustration
Contents

Rust Learning Path — Chapter 17. Cargo is more than a command that runs rustc. It is Rust's package manager, dependency resolver, build orchestrator, test runner and release tool. Understanding Cargo.toml, Cargo.lock, features and profiles is essential once you build real applications.

1. Cargo.toml is the package manifest

bash
[package] name = "service" version = "0.1.0" edition = "2024" [dependencies] serde = { version = "1", features = ["derive"] }

The manifest describes your package and tells Cargo which dependencies and build settings it needs.

2. Add dependencies

bash
cargo add serde --features derive cargo add tokio --features full cargo add anyhow

Cargo writes the corresponding dependency entries into the manifest.

3. Version requirements

A requirement such as serde = "1.0" normally allows compatible releases in the same major version. For application teams, commit Cargo.lock so everyone and CI use the same resolved versions.

4. Cargo.lock

Cargo.toml expresses allowed dependency ranges. Cargo.lock records the exact versions Cargo selected. Applications should normally commit it.

bash
cargo update cargo tree

cargo tree is extremely useful when investigating duplicate versions or unexpected transitive dependencies.

5. Optional dependencies and feature flags

bash
[features] default = [] postgres = ["dep:sqlx"] metrics = ["dep:prometheus"] [dependencies] sqlx = { version = "0.8", optional = true } prometheus = { version = "0.14", optional = true }

Compile with selected features:

bash
cargo build --features postgres,metrics

Features should represent additive capabilities. Avoid using mutually exclusive feature combinations when a normal configuration value would be clearer.

6. Feature-gated code

bash
#[cfg(feature = "metrics")] fn register_metrics() { println!("metrics enabled"); }

This code is compiled only when the feature is enabled.

7. Default features

bash
[features] default = ["json"] json = [] xml = []

Disable defaults when needed:

bash
cargo build --no-default-features

8. Development dependencies

Dependencies used only by tests and benchmarks belong under [dev-dependencies]:

bash
[dev-dependencies] tempfile = "3"

9. Build dependencies

Build scripts use [build-dependencies]. Keep build scripts small because they execute during compilation.

10. Git and path dependencies

bash
[dependencies] shared = { path = "../shared" } # or a Git source when necessary

Path dependencies are common in workspaces. Prefer released crates for reusable public libraries and pin external Git dependencies carefully.

11. Build profiles

Cargo provides dev and release profiles by default:

bash
[profile.release] lto = "thin" codegen-units = 1 panic = "abort"

Do not blindly enable every optimization. Measure build time, binary size and runtime performance first.

12. Workspace dependencies

bash
[workspace] members = ["api", "core"] [workspace.dependencies] serde = { version = "1", features = ["derive"] }

Members can inherit the dependency:

bash
[dependencies] serde.workspace = true

13. Useful Cargo commands

CommandPurpose
cargo checkFast type checking
cargo treeDependency graph
cargo updateRefresh compatible locked versions
cargo metadataMachine-readable workspace information
cargo build --releaseOptimized build

14. Security and dependency hygiene

  • Prefer well-maintained crates with clear ownership.
  • Review transitive dependencies with cargo tree .
  • Keep lockfiles in application repositories.
  • Update intentionally and run tests after dependency changes.
  • Use minimal feature sets to reduce unnecessary code and attack surface.

15. Mini lab

Create a CLI with an optional json feature. Build once with defaults, then with --no-default-features, and observe which code is compiled.

Key takeaways

Cargo's manifest defines what your package needs; the lockfile records the exact resolved graph; features make capabilities optional; profiles control build characteristics. Treat dependency configuration as production engineering, not boilerplate.

Did this help?

Yes No

Join the discussion

0 Comments

Ask questions, add context, or share what worked.

Sign in to join the discussion

No comments yet. Start the discussion.

More from Melochip Editorial

Related articles

Stay in the loop. Get new Melochip articles

Receive Melochip article updates when new articles are available. Explicit opt-in only.

No pre-checked boxes. Unsubscribe support is part of the subscriber foundation.