Top Cargo Subcommands For Rust Development

Jayson Lennon
Jayson Lennon
hero image

Cargo is the official package and dependency management tool for the Rust programming language.

It has a great deal of built-in features for assisting you with the development process, and it also supports further extension through subcommands.

In this post, we will be exploring some of the great things you can do with cargo itself, while also taking a look at useful cargo subcommands to supercharge your Rust development.

Sounds good? Awesome, so let's dive in!

Cargo basics

Here are some of the day-to-day commands that cargo provides:

# build your project
cargo build
cargo b
cargo build --release   # release mode

# check your code (emits compiler warnings & errors)
cargo check
cargo c

# run the project's tests
cargo test
cargo t
cargo test NAME          # run tests with NAME in the test name
cargo test --lib         # only test library code
cargo test --bin NAME    # test a binary named NAME
cargo test -j 1          # use single-threaded testing

# build documentation for your crate + depedencies
cargo doc      
cargo d
cargo doc --open   # open the docs in a browser

# make a new Rust project
cargo init         # new binary/application project
cargo init --lib   # new library project

# build & immediately run code
cargo run
cargo r
cargo run --example NAME   # run an example named NAME

# remove build artifacts (`target` directory)
cargo clean

Rust's crate ecosystem is another major benefit to using Rust.

Good news? cargo supports working with crates right out of the box!

# add latest version of CRATE_NAME
cargo add CRATE_NAME
# example: cargo add serde

# add a specific version of a crate
cargo add CRATE_NAME@VERSION
# example: cargo add serde@1

# add CRATE_NAME with features `feat_1` and `feat_2` enabled
cargo add CRATE_NAME -F feat_1 feat_2
# example cargo add serde -F derive

# add a crate from a git repo
cargo add --git URI
# example cargo add https://github.com/serde-rs/serde

# remove dependency on CRATE_NAME
cargo remove CRATE_NAME

Cargo subcommands

The built-in cargo commands are sufficient to build and manage your Rust code. However, sometimes it helps to have a little extra to make things even better.

That's where cargo subcommands come in.

Cargo subcommands

"Must-Have" `Cargo` subcommands

There are multiple subcommands available for esoteric scenarios like writing Postgres plugins or securing Linux applications with eBPF, but there are also general-purpose subcommands useful for most projects.

Here's a short list of subcommands that you can utilize in your own Rust projects today, and some quick notes on how they work.

cargo-update

Subcommands get installed using the cargo install command, but once installed there is no convenient way to update them.

Well, not any more! The cargo-update subcommand solves this problem by providing a subcommand to update your subcommands.

You can install it with:

cargo install cargo-update

Once installed, you can update your subcommands with:

cargo install-update -a

Simple! Now you can get the most up-to-date subcommands for working with your Rust projects.

cargo-watch

cargo install cargo-watch

cargo-watch is a source monitoring tool that will run cargo check (or any arbitrary shell command) whenever your source code changes.

Why care?

Well, this makes it easy to have a terminal open with the latest errors and warnings from the compiler.

cargo-nextest

cargo install --locked cargo-nextest

cargo-nextest is a test runner that provides an enhanced test result reporting interface, and runs up to 60% faster than the standard cargo test.

Not only that, but it also provides:

  • Better test filtering
  • Finds slow-running tests and tests that don't perform proper cleanup
  • And can identify tests which have intermittent failures

Once installed, you can run your project's tests with nextest by using

cargo nextest run

Sidenote: cargo-nextest is a drop-in replacement for cargo test but with added features.

cargo-readme

cargo install cargo-readme

Every project needs a README.md file, but writing them can be a pain.

cargo-readme handles this by generating a README.md file from the documentation comments in your source code.

To get a usable README.md, just run:

cargo readme > README.md

Also? cargo-readme uses templates to generate the README.md file, so if you have a style that you prefer, or if you simply want to include additional information in your READMEs, you can create your own template with these additions.

cargo-make

cargo install cargo-make

cargo-make is a command runner that provides two important things:

  1. The creation of commands or "scripts", similar to npm scripts
  2. Defining and execution of processes

This enables the creation of workflows which cargo-make can then execute.

For example

cargo-make enables the combination of cargo test, cargo format, and cargo build into a single command such as custom-build.

This means that whenever we run cargo make custom-build, all three commands will run, which can be incredibly helpful.

While Command dependencies allows creation of sequential workflows that will abort if any command in the sequence fails. An example of this could be making cargo test depend on cargo check producing no warnings, before it runs any further.

The best part of cargo-make is the support for writing scripts to do whatever tasks the project requires.

Why? Well, since Rust is multi-platform, cargo-make comes with support for duckscript and Rust code for scripting. This then allows the scripts to run on any system that supports compiling Rust code!

cargo-make has a comprehensive amount of options, so be sure to check out the usage section of the docs in order to get the most out of the tool.

cargo-expand

cargo install cargo-expand

When working with macros, it can sometimes be difficult to determine what code gets generated.

working with macros

But with cargo-expand, you can get a printout of the code generated by macros, which makes macro development much easier.

Corrections / Auditing subcommands

One of Rust's biggest strengths is being able to produce correct code.

Here's a non-exhaustive list of the subcommands I've found to be the most useful.

cargo-tarpaulin

cargo install cargo-tarpaulin

cargo-tarpaulin generates code coverage reports.

These reports allow you to discover how much of your code has test coverage and it identifies covered lines.

By default, tarpaulin outputs the report in the terminal, but it supports different output formats.

For example

If you want to produce an HTML report, you can do so with:

cargo tarpaulin -o html

tarpaulin will then output the report to tarpaulin-report.html in the project root directory and you can view the report by opening it in your browser, or with the open command (OSX/Linux): open tarpaulin-report.html.

cargo-semver-checks

cargo install cargo-semver-checks

Rust crates use Semantic Versioning (SemVer) to communicate when breaking changes will occur, and Semantic versioning specifies versions using the triple MAJOR.MINOR.PATCH.

  • MAJOR identifies an API breaking change
  • MINOR is a backwards compatible change in functionality, and
  • PATCH handles backwards compatible bugfixes

The cargo-semver-checks subcommand will compare your code to a baseline and identify changes that would result in violating SemVer.

This means that if you make a change to your code and don't update the version number as indicated by SemVer, cargo-semver-checks will list out the problems and identify which part of the SemVer triple to use for the listed issue.

For example

Adding or removing an enum variant is a breaking API change because match blocks are exhaustive.

For this reason, adding or removing a variant requires the MAJOR version of the crate to increase. And so, if you don't update the MAJOR version number, and then make the change to the enum, cargo-semver-checks will produce an error indicating that there is a change with enum variants.

The error warning output will look something like this:

Description:
A publicly-visible enum without #[non_exhaustive] has a new variant.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new
       impl: https://github.com/obi1kenobi/cargo-semver-check/tree/v0.15.2/src/queries/enum_variant_added.ron

Failed in:
  variant Messages:Goodbye in src/main.rs:3
       Final [   0.037s] semver requires new major version: 1 major and 0 minor checks failed

Important: By default, semver-checks will use code published to the crates.io registry as a baseline for comparison.

However, you can use the --baseline-rev flag to set the baseline to a git revision, like so:

cargo semver-checks check-release --baseline-rev REVISION_HASH -v

This makes it easier to update versions on private crates, or for crates that aren't yet published to crates.io.

cargo-outdated

cargo install --locked cargo-outdated

cargo-outdated is a straightforward subcommand for discovering outdated dependencies.

Running cargo outdated will list out all of your dependencies that have gone out of date, along with the version you are using, and the latest version available.

You can use then this information to decide when you want to update the dependencies of your application.

cargo-audit

Security is a critical part of every software project, but it can be hard to stay on top of it, if it's not your main focus.

Good news? cargo-audit provides a way to audit the current security of your project, by checking all dependencies against known vulnerabilities published to the RustSec Advisory Database.

You simply run cargo audit, and then it will check the database against your code. If any of your dependencies have matching versions, you'll get a report indicating what action to take in order to fix the vulnerability.

Safety first!

cargo-license

cargo install cargo-license

Maintaining proper licensing is also a critical part of software development.

Whether you are working on a commercial product or an open source project, you'll need to make sure you adhere to the code licenses.

cargo-license helps with this by enumarating all of your dependencies and producing a report with all the licenses used, and which crates use which licenses.

cargo-deny

cargo install --locked cargo-deny && cargo deny init

Most of the subcommands mentioned in this section have reported information that you can then evaluate yourself and use to make a decision, but cargo-deny changes this by instead reporting errors when some criteria aren't met.

The criteria cargo-deny supports are:

  • licenses
  • crate bans
  • security advisories, and
  • crate sources

For example

If you want your project to use MIT licensed code, you can configure cargo-deny to check all the licenses. Then, if any dependencies have a license other than MIT, it will produce an error.

Simple!

If you combine this with cargo-make and CI, you can even create automations that ensure your project meets the standards you specify.

cargo-geiger

cargo install cargo-geiger

unsafe code blocks in Rust allow for operations that can introduce security risks that aren't otherwise possible in safe Rust.

Developers take extra effort to ensure that unsafe blocks don't introduce security problems, but it is still a potential risk. For this reason, some developers may want to keep unsafe code to a minimum in order to reduce the potential attack surface of an application.

cargo-geiger helps with this by generating a report which lists the total count of unsafe code present in all dependencies.

Packaging subcommands

Rust can run on different operating systems, and the packaging standard differs across these systems.

cargo subcommands are here to make it easy to generate packages right from cargo:

System / Environment Subcommand
Arch Linux cargo-aur
Debian/Ubuntu cargo-deb
Fedora/CentOS/RHEL cargo-generate-rpm
Windows cargo-wix
Android cargo-apk
Gentoo cargo-ebuild
OSX cargo-bundle
WASM cargo-web
WASI cargo-wasi

So what are you waiting for? Go try these `Cargo` subcommands today!

As you can see, these Cargo subcommands can be incredibly helpful to manage your own Rust projects and dependencies, as well as streamline your workflow.

If you're not entirely sure how to use these subcommands, or if you simply want to learn more about programming with Rust, then check out my complete Rust Programming course.

In it, you'll learn how to get to the level where you can code and build your own real-world applications using Rust so that you can get hired this year.

Start my Rust course for free here. (No signup or credit card required, just start learning!)

BONUS: More Rust tutorials, guides & resources

If you've made it this far, you're clearly interested in Rust so definitely check out all of my Rust posts and content:

More from Zero To Mastery

Top 15 Rust Projects To Elevate Your Skills preview
Top 15 Rust Projects To Elevate Your Skills

From beginner to advanced, these are the best Rust projects to push your skills, grow your confidence, and wow potential employers. Check them out now!

53 Rust Interview Questions + Answers (Easy, Medium, Hard) preview
53 Rust Interview Questions + Answers (Easy, Medium, Hard)

Are you ready for your Rust interview? Try out these 53 Rust programming interview questions to find out. Or use them as practice questions to help you prepare!

Rust Programming Language: AMA Deep Dive preview
Rust Programming Language: AMA Deep Dive

Jayson Lennon breaks down the most common asked questions about the Rust programmming language in this developer AMA.