SyntaxStudy
Sign Up
Rust Managing Dependencies in Cargo.toml
Rust Beginner 1 min read

Managing Dependencies in Cargo.toml

Dependencies are declared in the `[dependencies]` section of `Cargo.toml`. You specify the crate name and a version requirement using Semantic Versioning. The caret requirement `"^1.2.3"` (the default when you write `"1.2.3"`) allows any compatible version — one that does not change the leftmost non-zero digit. `cargo add serde` is the command-line shortcut to add a dependency without editing the file manually. The `Cargo.lock` file records the exact versions of every dependency and transitive dependency that were resolved when you last ran `cargo build`. This file should be committed for binary projects to ensure reproducible builds but is conventionally gitignored for library crates. Running `cargo update` finds newer compatible versions and updates the lock file accordingly. Features allow crates to offer optional functionality that consumers can opt into. You enable features with `serde = { version = "1", features = ["derive"] }`. This keeps compile times and binary sizes down by only compiling what is needed. The `optional = true` field in `[dependencies]` lets a crate expose a feature that, when enabled by a downstream consumer, activates the dependency.
Example
# Cargo.toml — real-world dependency configuration

[package]
name = "my_app"
version = "0.2.0"
edition = "2021"

[dependencies]
# Exact caret requirement (^1 means >=1.0.0, <2.0.0)
serde = { version = "1", features = ["derive"] }
serde_json = "1"

# Range requirement
log = ">=0.4, <0.5"

# Git dependency (pinned to a specific commit)
# my_lib = { git = "https://github.com/user/my_lib", rev = "abc1234" }

# Path dependency (local crate)
# utils = { path = "../utils" }

# Optional dependency (activated by a feature flag)
# rayon = { version = "1", optional = true }

[dev-dependencies]
pretty_assertions = "1"   # only available in tests

[features]
default = []
# parallel = ["rayon"]    # enable with: cargo build --features parallel

# --- src/main.rs ---
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Config {
    host: String,
    port: u16,
    debug: bool,
}

fn main() {
    let cfg = Config { host: "localhost".into(), port: 8080, debug: true };
    let json = serde_json::to_string_pretty(&cfg).unwrap();
    println!("{json}");

    let decoded: Config = serde_json::from_str(&json).unwrap();
    println!("decoded host: {}", decoded.host);
}