Skip to main content
  1. Languages/
  2. Rust Guides/

Beyond Cargo: 5 Essential Rust CLI Tools for Modern Development

Jeff Taakey
Author
Jeff Taakey
21+ Year CTO & Multi-Cloud Architect.

The Rust ecosystem has matured significantly by 2025. While cargo remains the envy of other programming languages for its seamless dependency management and build orchestration, relying solely on the default toolchain limits your potential.

For mid-to-senior developers, efficiency isn’t just about writing code; it’s about the feedback loop. How fast can you test? How deep can you debug a macro? How quickly can you spot a performance bottleneck?

In this article, we are cutting through the noise to look at 5 essential Rust CLI tools that should be in your terminal right now. These aren’t just “nice-to-haves”—they are force multipliers for professional engineering.

Prerequisites & Environment
#

Before we dive in, ensure your environment is ready. We assume you are running a Unix-like environment (Linux, macOS, or WSL2 on Windows) and have the standard Rust toolchain installed.

System Requirements:

  • Rust: Stable channel (1.83+ recommended for latest features).
  • OS: Linux/macOS/WSL2.

To verify your setup, run:

rustc --version
cargo --version

Most of the tools below are installed via cargo install. A pro-tip for 2025: consider using cargo-binstall if you want binary installations without waiting for local compilation.

# Optional: Installs binaries directly, saving compilation time
cargo install cargo-binstall

1. Cargo Watch: The Continuous Feedback Loop
#

If you are still manually typing cargo run after every file save, you are breaking your flow state. cargo-watch is the absolute gold standard for Test-Driven Development (TDD) and rapid prototyping in Rust.

It monitors your source directory and triggers commands whenever a file changes.

Installation
#

cargo install cargo-watch

Usage & Best Practices
#

The most basic usage is running your application on change:

cargo watch -x run

However, senior developers often chain commands to catch compile errors before running heavy tests. The following command first checks syntax, then runs tests, and finally runs the application:

cargo watch -x check -x test -x run

Why it matters: It drastically reduces context switching. You stay in your IDE, save the file, and glance at the terminal. If it’s green, you keep coding.


2. Cargo Expand: Demystifying Macros
#

Rust macros are powerful, but they can feel like “magic.” When a #[derive(Serialize)] fails or a tokio::main behaves unexpectedly, compiler errors pointing to macro lines are often unhelpful.

cargo-expand allows you to see the code after macro expansion but before compilation. It is indispensable for debugging procedural macros.

Installation
#

You will need the nightly toolchain installed (even if your project uses stable), as expansion relies on nightly compiler internals.

rustup toolchain install nightly
cargo install cargo-expand

The “Aha!” Moment
#

Imagine you have a simple struct with a derive macro:

// main.rs
#[derive(Debug)]
struct User {
    id: u32,
    username: String,
}

fn main() {
    let u = User { id: 1, username: "RustAce".to_string() };
    println!("{:?}", u);
}

Run expansion on this file:

cargo expand main

Output: You will see the actual impl fmt::Debug for User block that Rust generated. This visibility is crucial when working with complex libraries like sqlx, serde, or yew.


3. Cargo Nextest: Parallel Testing on Steroids
#

By 2025, mono-repos and large workspaces are common. The standard cargo test runner executes tests sequentially (mostly) and offers limited UI. Enter cargo-nextest, a next-generation test runner that is significantly faster and cleaner.

It identifies flaky tests, runs partitions in parallel, and provides a much better CI/CD experience.

Installation
#

cargo install cargo-nextest
# Or via binstall for speed
cargo binstall cargo-nextest

Performance Comparison
#

Why switch? Let’s compare the standard runner with Nextest.

Feature Standard cargo test cargo nextest
Execution Model Mostly Serial / Limited Threads Process-per-test (High Parallelism)
Flakiness Detection Manual Built-in Retries & Detection
Output UI Verbose, intertwined logs Clean, grouped, progress bar
CI Integration Basic JUnit support First-class JUnit & GitHub Actions
Test Filtering Basic string matching Advanced filter expressions

Execution Flow
#

The architecture of Nextest is what makes it superior for modern multi-core machines.

graph TD A[Start Tests] --> B{Analyze Dependency Graph} B --> C[Build Test Binaries] C --> D{Test Runner} subgraph Execution Engine D --> E[Process 1: Unit Test A] D --> F[Process 2: Unit Test B] D --> G[Process 3: Integration Test C] D --> H[Process 4: Doc Test D] end E --> I[Aggregator] F --> I G --> I H --> I I --> J[Final Report & Retry Logic] style D fill:#e1f5fe,stroke:#01579b,stroke-width:2px style J fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px

To run it, simply replace test with nextest run:

cargo nextest run

4. Flamegraph: Visualizing Performance Bottlenecks
#

“It feels slow” is not an engineering metric. To optimize Rust code, you need sampling profilers. While perf on Linux is powerful, interpreting raw text output is tedious.

cargo-flamegraph wraps perf (on Linux) or dtrace (on macOS) to generate beautiful, interactive SVG visualizations of your call stack.

Installation
#

# Note: Linux users may need 'perf' installed via apt/dnf
cargo install flamegraph

Usage
#

To profile your application, you typically want to profile the release build (debug builds have too much noise).

cargo flamegraph --root --bench my_benchmark
# or simply for a binary
cargo flamegraph --bin my_app

This command runs your binary, collects stack samples, and outputs a flamegraph.svg. Open this in Chrome or Firefox. The width of a bar represents the time spent in that function. Look for wide “plateaus”—these are your optimization targets.

Warning: Ensure you enable debug symbols in your release profile for meaningful function names!

Add this to Cargo.toml:

[profile.release]
debug = true

5. Cargo Audit: Security in the Supply Chain
#

In the modern web, dependencies are liabilities. Supply chain attacks have become a primary vector for compromising applications. As a senior developer, you are responsible for the security of your crate graph.

cargo-audit checks your Cargo.lock file against the RustSec Advisory Database.

Installation
#

cargo install cargo-audit

Integrating into CI
#

While you can run cargo audit locally, its real power is in your CI pipeline.

cargo audit

If a vulnerability is found (e.g., in an old version of openssl or tokio), the command fails with a non-zero exit code.

Common Pitfall: Sometimes an advisory exists for a vulnerability that doesn’t affect your specific usage. You can ignore specific advisories in an audit.toml config file, but do so with extreme caution.

# audit.toml
[advisories]
ignore = ["RUSTSEC-2025-0001"] # Only if you verified you are safe!

Summary
#

The difference between a junior and a senior Rust developer often lies in their tooling. While the compiler is your best friend, these CLI tools act as your extended team:

  1. Cargo Watch: Your productivity partner.
  2. Cargo Expand: Your debugger for the “magic” parts.
  3. Cargo Nextest: Your speed booster for validation.
  4. Flamegraph: Your performance analyst.
  5. Cargo Audit: Your security guard.

Next Steps
#

If you haven’t installed these yet, dedicate 15 minutes today to setting them up. Configure aliases in your .zshrc or .bashrc (e.g., alias cw="cargo watch -x check -x test") to make them muscle memory.

Did I miss your favorite tool? Let me know in the comments or check out our guide on “Advanced Async Rust Patterns” coming next week.