Sections
IntroductionGetting StartedWhat is Rust?InstallationYour First ProjectIDE SetupRust Language FundamentalsVariables and TypesFunctions and Control FlowOwnershipBorrowing and SlicesStructs and EnumsError HandlingCollectionsClosures and IteratorsTraits and GenericsModules and CratesProject Setup and ToolingCargo In DepthDependenciesTestingDaily WorkflowPyO3 and LogferryPyO3 OverviewExposing FunctionsExposing ClassesError Handling in PyO3Multithreading and the GILlogferry WalkthroughDistributionCargo CheatsheetReferencePython → Rust CheatsheetTroubleshooting
Dependencies
4 min read
Prerequisites: Cargo In Depth
Next: Testing
This article covers how to find, add, and manage Rust dependencies — the equivalent of pip, PyPI, and requirements.txt.
Finding Packages
- crates.io — the official Rust package registry (like PyPI)
- lib.rs — better search UI and category browsing
- docs.rs — auto-generated API docs for every published crate version
Search from the terminal:
cargo search "json parser"
Adding Dependencies
# Add a dependency (updates Cargo.toml and fetches the crate)
cargo add serde --features derive
cargo add serde_json
cargo add tokio --features full
# Remove a dependency
cargo remove tokio
# Update all dependencies to latest compatible versions (respects semver)
cargo update
# Update one specific dependency
cargo update -p serde
# See the full dependency tree (like pipdeptree)
cargo tree
# Check for outdated dependencies (needs cargo-outdated)
cargo install cargo-outdated
cargo outdated
# Check for known security vulnerabilities
cargo install cargo-audit
cargo audit
Python to Rust Crate Analogues
| Python library | Rust crate | Purpose |
|---|---|---|
json |
serde_json |
JSON parse / serialise |
pydantic |
serde + derive |
Struct ↔ JSON/YAML/etc. |
requests |
reqwest |
HTTP client |
asyncio |
tokio |
Async runtime |
click / argparse |
clap |
CLI argument parsing |
logging |
tracing |
Structured logging |
datetime |
chrono |
Date and time |
pathlib |
std::path::PathBuf |
File paths (stdlib) |
re |
regex |
Regular expressions |
uuid |
uuid |
UUID generation |
python-dotenv |
dotenvy |
.env file loading |
psycopg2 |
sqlx |
PostgreSQL async |
redis-py |
redis |
Redis client |
pytest |
built-in #[test] + cargo test |
Testing |
PyO3 / cffi |
pyo3 |
Python ↔ Rust bridge |
Specifying Version Requirements
Rust uses semantic versioning. In Cargo.toml:
[dependencies]
serde = "1" # >= 1.0.0, < 2.0.0 (compatible release)
serde = "1.0" # >= 1.0.0, < 1.1.0 (more restrictive)
serde = "=1.0.195" # exact version
serde = ">=1.0, <2" # explicit range
serde = "*" # any version (avoid — too permissive)
Features
Some crates have optional features (like extras in Python):
[dependencies]
serde = { version = "1", features = ["derive"] } # enables #[derive(Serialize, Deserialize)]
tokio = { version = "1", features = ["full"] } # enables all tokio features
pyo3 = { version = "0.20", features = ["extension-module"] }
# Add a crate with a specific feature enabled
cargo add serde --features derive
Cargo.lock — Exact Reproducible Builds
Cargo.lock records the exact version of every transitive dependency, like pip freeze. Cargo updates it whenever you run cargo build with new or changed dependencies.
Convention:
- Binary projects (executables): commit
Cargo.lockso every developer and CI run uses identical versions. - Library crates (no
fn main):.gitignoreCargo.lock— let downstream users pick compatible versions within your declared ranges.
logferry is a library (from Cargo's perspective), but it has a Python-facing binary build. Committing Cargo.lock is reasonable either way.
Dev and Build Dependencies
# Dev dependencies — used in tests and examples, not shipped to users
[dev-dependencies]
pretty_assertions = "1" # nicer diff output in test failures
tempfile = "3" # temporary files and directories for tests
# Build dependencies — used by build.rs scripts only
[build-dependencies]
cc = "1" # C compiler wrapper (for crates with C code)
Private and Path Dependencies
[dependencies]
# Local path — useful for multi-crate workspaces or developing two crates together
metrics_lib = { path = "../metrics_lib" }
# Git dependency — pin to a specific commit or tag
my_crate = { git = "https://github.com/user/my_crate", tag = "v1.2.0" }
Workspaces
For projects with multiple related crates (e.g. a binary + a library), use a Cargo workspace:
# Workspace-level Cargo.toml (at the repo root)
[workspace]
members = [
"logferry",
"logferry-cli",
"metrics_lib",
]
# Build all workspace members
cargo build --workspace
# Test all workspace members
cargo test --workspace
See Also
- Testing — using dev dependencies in tests
- Cargo Cheatsheet — all cargo commands
- Python → Rust Cheatsheet — full library analogy table