RustUsing crates.io

Using crates.io

crates.io is the official package registry for Rust. It hosts over 140,000 published crates — libraries and tools that the Rust community has written and shared. Cargo, Rust's build tool, integrates with crates.io directly, so adding a dependency is a matter of editing one line in Cargo.toml.

This page covers everything you need to find, add, manage, and eventually publish crates.

Adding Dependencies

Open your project's Cargo.toml and add the crate name and version under the [dependencies] section:

TOML
[dependencies]
serde = { version = "1", features = ["derive"] }
rand  = "0.8"
anyhow = "1"

Run cargo build (or any cargo command) and Cargo will download and compile the new dependencies automatically. The first build fetches the source; subsequent builds use a local cache.

From Rust 1.62 you can also use the cargo add subcommand to add and resolve a dependency from the command line:

Bash
# Add the latest compatible version
cargo add serde

# Add with features
cargo add serde --features derive

# Add a specific version
cargo add rand@0.8
    Updating crates.io index
      Adding serde v1.0.203 to dependencies
             Features:
             + derive
             + std
             - alloc
             ...
Semantic Versioning

Rust crates follow Semantic Versioning (SemVer): MAJOR.MINOR.PATCH.

  • PATCH bump — backwards-compatible bug fixes
  • MINOR bump — backwards-compatible new features
  • MAJOR bump — breaking changes

Cargo version specifiers:

Specifier

Meaning

Example range

^1.2.3 (default)

Compatible with 1.2.3 — any 1.x.y where x>=2 or y>=3

=1.2.3, <2.0.0

^0.2.3

Pre-1.0 compatibility — any 0.2.x

=0.2.3, <0.3.0

~1.2.3

Patch-level only

=1.2.3, <1.3.0

=1.2.3

Exact version

1.2.3 only

=1.2, <1.5

Range

1.2.0 to 1.4.x

Any version (avoid in libraries)

No constraint

Note
For versions below 1.0, the caret specifier is more conservative: ^0.2allows any 0.2.x but not 0.3.0, because breaking changes may occur in minor version bumps before a stable 1.0 is released.
Cargo.lock and Reproducible Builds

When Cargo resolves dependencies it writes the exact versions it chose to Cargo.lock. On subsequent builds Cargo reads the lock file instead of re-resolving — this guarantees reproducible builds.

Convention:

  • Application (binary crate): commit Cargo.lock to version control.
  • Library crate: do not commit Cargo.lock — let downstream users resolve.

Bash
# Update all dependencies to the latest versions within your constraints
cargo update

# Update only a specific crate
cargo update --precise 0.8.5 rand
Inspecting the Dependency Tree

Bash
# Print the full dependency tree
cargo tree

# Show only dependencies that include a specific crate
cargo tree --invert rand

# Show duplicated crate versions (a common source of binary bloat)
cargo tree --duplicates
my-project v0.1.0
├── anyhow v1.0.86
├── rand v0.8.5
│   ├── rand_chacha v0.3.1
│   │   ├── ppv-lite86 v0.2.17
│   │   └── rand_core v0.6.4
│   └── rand_core v0.6.4
└── serde v1.0.203
    └── serde_derive v1.0.203 (proc-macro)
Auditing for Security Vulnerabilities

Bash
# Install the audit tool once
cargo install cargo-audit

# Check your dependency tree against the RustSec advisory database
cargo audit
    Fetching advisory database from https://github.com/RustSec/advisory-db.git
      Loaded 737 security advisories (from ~/.cargo/advisory-db)
    Scanning Cargo.lock for vulnerabilities (133 crate dependencies)
        No vulnerable packages found
Tip
Add cargo audit to your CI pipeline so that newly discovered vulnerabilities in your dependencies are caught automatically before they reach production.
Dev and Build Dependencies

Not all dependencies are needed at runtime. Cargo supports two additional dependency sections:

TOML
[dependencies]
serde = { version = "1", features = ["derive"] }

[dev-dependencies]
# Only compiled for tests and benchmarks — not included in release binaries
criterion = "0.5"
proptest = "1"

[build-dependencies]
# Only used in build.rs scripts — not included in the final binary
bindgen = "0.69"
cc = "1"
Feature Flags

Many crates expose features — optional capabilities that you opt into. This keeps the default build lean and compile times fast. You activate features in Cargo.toml:

TOML
[dependencies]
# Activate only the features you actually need
tokio     = { version = "1", features = ["rt-multi-thread", "macros", "io-util"] }
serde     = { version = "1", features = ["derive"] }
reqwest   = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }

Use default-features = false to opt out of a crate's default feature set and only enable what you need — useful for embedded or WASM targets that cannot use std-dependent features.

Finding Good Crates
  • crates.io (crates.io) — the official registry. Search by keyword; shows download counts and recent activity.

  • docs.rs (docs.rs) — auto-generated API documentation for every published crate. The canonical place to read a crate's API.

  • lib.rs (lib.rs) — a curated, searchable alternative front-end for crates.io with better category browsing.

  • blessed.rs (blessed.rs) — a community-maintained guide to the "blessed" (recommended) crates for common tasks.

  • are we X yet sites — e.g. arewewebyet.org, arewegameyet.com — show the ecosystem maturity for specific domains.

Must-Know Crates

Crate

Purpose

serde + serde_json

Serialisation and deserialisation — de facto standard

tokio

Async runtime — the most widely used async executor

reqwest

HTTP client built on tokio

anyhow

Ergonomic error handling for applications

thiserror

Derive macros for custom Error types in libraries

clap

Command-line argument parsing

rayon

Data-parallel iterators for CPU-bound workloads

chrono

Date and time handling

uuid

UUID generation and parsing

rand

Random number generation

tracing

Structured, async-aware logging and instrumentation

sqlx

Async SQL with compile-time checked queries

Publishing a Crate
  1. Create an account on crates.io and generate an API token under Account Settings.

  2. Authenticate locally: cargo login <your-token>

  3. Fill in the required fields in Cargo.toml: name, version, edition, description, license, and repository.

  4. Ensure your crate builds cleanly: cargo build && cargo test

  5. Do a dry run to catch issues before uploading: cargo publish --dry-run

  6. Publish: cargo publish

  7. Documentation is automatically generated and published to docs.rs within minutes.

TOML
# Minimum required Cargo.toml fields for publishing
[package]
name        = "my-awesome-crate"
version     = "0.1.0"
edition     = "2021"
description = "A short description of what this crate does"
license     = "MIT OR Apache-2.0"
repository  = "https://github.com/yourname/my-awesome-crate"
readme      = "README.md"
keywords    = ["example", "tutorial"]
categories  = ["development-tools"]
Yanking a Version

If you publish a version with a serious bug or a security vulnerability, you can yank it. Yanking marks a version as "do not use for new projects" without removing it — existing users who already have that version in their Cargo.lock are unaffected, but new cargo add and cargo update commands will skip the yanked version.

Bash
# Yank a specific version
cargo yank --version 0.1.0 my-awesome-crate

# Un-yank if you made a mistake
cargo yank --undo --version 0.1.0 my-awesome-crate
Warning
Yanking is not deleting. The source code of a yanked version remains on crates.io permanently. Never publish secrets, passwords, or private keys to crates.io — they cannot be truly removed.
Success
crates.io and Cargo together give Rust one of the most ergonomic dependency management stories in any language. Semantic versioning, the lock file,cargo audit, and docs.rs combine to make adding, updating, and trusting third-party code straightforward.