23.2 The Cargo Command-Line Interface (CLI)

Cargo is primarily used via the command line. You can verify your installation and see available commands:

cargo --version
cargo --help

Below are some of the most frequently used Cargo commands.

23.2.1 cargo new and cargo init

These commands initialize a new Rust project (package).

  • cargo new <project_name>: Creates a new directory named <project_name> containing a minimal Cargo.toml file and a src/ directory with a basic main.rs (for a binary package/crate) or lib.rs (for a library package/crate). Crucially, it also initializes a Git repository by default (complete with a .gitignore file), as most Rust projects are managed with Git. This practice facilitates collaboration and version tracking, often on platforms like GitHub.
  • cargo init [<path>]: Initializes a Cargo package structure within an existing directory. If <path> is omitted, it uses the current directory. It will also create a .gitignore file if a Git repository is not already present but will not initialize a new Git repository if one doesn’t exist.

Use the --lib flag to create a library package instead of the default binary (application) package:

# Create a new binary application package named 'hello_world'
cargo new hello_world

# Create a new library package named 'my_utils'
cargo new my_utils --lib

# Initialize the current directory as a Cargo package (defaults to binary)
cargo init

# Initialize './existing_lib_dir' as a library package
cargo init --lib ./existing_lib_dir

23.2.2 cargo build and cargo run

These commands compile and execute your code.

  • cargo build: Compiles the current package, including its crates. By default, it builds in debug mode, which prioritizes faster compilation times over runtime performance and includes debugging information. Output artifacts are placed in the target/debug/ directory.
  • cargo run: Compiles the package (if necessary) and then executes the resulting binary (only applicable to binary packages/crates). Also defaults to debug mode.
# Build the package in debug mode
cargo build

# Build and run the package's default binary in debug mode
cargo run

Release Mode

For production builds or performance testing, use release mode. This enables more aggressive compiler optimizations, resulting in slower compilation but faster runtime performance and smaller binaries. Debug information is typically omitted.

# Build with release optimizations
cargo build --release

# Build and run in release mode
cargo run --release

Release artifacts are placed in a separate target/release/ directory. Incremental compilation behaves differently in release mode, as discussed in Section 23.5.1.

23.2.3 cargo check

This command quickly checks your code for compilation errors without generating any executable code. It performs parsing, type checking, and borrow checking on the crates within your package.

cargo check

cargo check is significantly faster than cargo build, especially for larger projects, because it skips the code generation (LLVM) phase. It’s useful for getting rapid feedback during development. It also benefits from incremental checking.

23.2.4 cargo clean

Removes the target/ directory, deleting all compiled artifacts (executables, libraries, intermediate files) for the current package.

cargo clean

This is useful when you suspect build issues might be related to stale artifacts, need to force a full rebuild of the package’s crates, or want to free up disk space.

23.2.5 cargo add, cargo remove, cargo upgrade

These commands manage dependencies listed in your Cargo.toml. They operate on dependency packages.

  • cargo add <package_name>: Adds a dependency on the latest compatible version of the package <package_name> from Crates.io to your Cargo.toml.
  • cargo remove <package_name>: Removes a dependency package from Cargo.toml.
  • cargo upgrade: Updates dependencies in Cargo.toml to their latest compatible versions according to SemVer rules. (Note: This command is provided by the external cargo-edit tool, see Section 23.2.10).
# Add the 'serde' package as a dependency
cargo add serde

# Add 'rand' as a development-only dependency package (for tests, examples)
cargo add rand --dev

# Add a specific version of the 'serde' package with a feature enabled
cargo add serde --version "1.0.150" --features "derive"

# Remove the 'rand' package
cargo remove rand

These commands modify Cargo.toml and automatically update Cargo.lock (see Section 23.4.3). Before Rust 1.62, cargo add and remove were part of the external cargo-edit tool. They are now built-in.

23.2.6 cargo fmt

Formats your package’s Rust code according to the community-standard style guidelines using the rustfmt tool.

cargo fmt

Running cargo fmt regularly helps maintain a consistent code style across the project’s crates, reducing cognitive load and preventing style-related noise in code reviews and version control history.

23.2.7 cargo clippy

Runs Clippy, Rust’s official collection of lints. Clippy provides suggestions to improve code correctness, performance, style, and idiomatic usage within your package’s crates.

cargo clippy

Clippy often catches potential bugs or suggests better ways to express logic. It’s highly recommended to run clippy as part of your development workflow and CI process.

23.2.8 cargo fix

Automatically applies suggestions made by the Rust compiler (rustc) or Clippy to fix warnings or simple errors in your package’s code.

# Apply compiler suggestions
cargo fix

# Apply suggestions, even with uncommitted changes (use with caution)
# (This assumes changes are staged or you accept working with a dirty tree)
cargo fix --allow-dirty

Always review the changes made by cargo fix before committing them to your version control system.

23.2.9 cargo doc

Generates HTML documentation for your package and its dependencies based on documentation comments in the source code of its crates.

# Generate documentation (output in target/doc/)
cargo doc

# Generate documentation and open the main page in a browser
cargo doc --open

# Generate docs only for your package's own crates (not dependencies)
cargo doc --no-deps

Documentation generation is covered further in Section 23.8.

23.2.10 Extending Cargo: cargo install and External Tools

Cargo can be extended with custom subcommands. You can install additional tools distributed as binary packages using cargo install.

  • cargo install <package_name>: Downloads and installs a binary package globally (typically in ~/.cargo/bin/). Cargo builds the binary crate within the package and places the resulting executable. Ensure this directory is in your system’s PATH.
  • External Subcommands: If you install a binary named cargo-foo, you can invoke it as cargo foo.

Examples of useful tools installable via cargo install:

  • cargo-edit: Provides cargo upgrade, cargo set-version, and other convenient commands for managing Cargo.toml dependencies.
  • cargo-outdated: Checks for dependency packages that have newer versions available on Crates.io than specified in Cargo.lock.
  • cargo-audit: Audits Cargo.lock for dependency packages with known security vulnerabilities reported to the RustSec Advisory Database.
  • cargo-expand: Shows the result of macro expansion within your code.
  • cargo-miri: Runs your code (including unsafe code) in an interpreter (Miri) to detect certain kinds of Undefined Behavior (UB). Requires installing the Miri component: rustup component add miri.
# Install the cargo-edit package (and its binary crate)
cargo install cargo-edit

# Now you can use 'cargo upgrade'
cargo upgrade

# Install Miri and run
rustup component add miri
cargo miri run