How to Use Cargo Nextest: The Beginner’s Guide (First Run, the Filter Lesson, Retries, and CI)

CodexFuse Team · 2026-11-02T00:07:32.184Z · 16 min read min read

Run Rust tests up to 3x faster: install cargo nextest, master filters and filtersets, retry flaky tests, add JUnit reports, and wire it into CI.

How to Use Cargo Nextest: The Beginner's Guide (First Run, the Filter Lesson, Retries, and CI)

Learning how to use cargo nextest is the fastest upgrade a Rust developer can make to their testing workflow. Cargo Nextest is a next-generation Rust test runner that takes the test binaries your project already compiles and runs each test in its own isolated process, scheduling tests across binaries in parallel. This cargo nextest tutorial takes you from zero to a complete setup: install, first run, the filter lesson, retries for flaky tests, profiles, archiving, and CI. One thing to get straight before we start: the tool's binary is called cargo-nextest, and you invoke it as cargo nextest — everything in this guide uses that form. If you are new to the Rust ecosystem in general, our Tauri beginner guide covers Rust prerequisites and tooling setup; Tauri builds desktop apps in Rust, while Nextest runs Rust's tests — different layers of the same language.

What Is Cargo Nextest, Exactly?

Cargo Nextest is a next-generation test runner for Rust that replaces the execution layer of cargo test, not Cargo itself. Cargo still compiles your test binaries the usual way; Nextest takes over at run time and executes each test in its own process, scheduling tests across all your test binaries in parallel. The official site, nexte.st, states it runs up to 3 times faster than cargo test while giving cleaner, per-test output. The current release is cargo-nextest 0.9.150 (released October 26, 2026, per the official changelog and GitHub releases). The mental model to keep in your head: Nextest does not replace the libtest harness — it uses the same test binaries Cargo compiles and runs them with a smarter, process-per-test execution model.

Is Cargo Nextest a Replacement for cargo test?

Yes — Nextest replaces the test-runner half of cargo test, and most developers use it as a drop-in replacement. The official docs say it plainly: "Nextest runs each test in its own process," while "cargo test runs many tests in the same process." That single architectural difference is the source of nearly every advantage below. Familiar libtest arguments still pass through after --, so cargo nextest run -- --ignored behaves like its cargo test equivalent. Here is the full nextest vs cargo test comparison:

Behaviorcargo test (libtest)cargo nextest
Execution modelMany tests share one process per test binaryEach test runs in its own process
ParallelismParallel only within one binary; binaries run seriallyTests scheduled across all binaries in parallel
SpeedBaselineUp to 3x faster (official claim; 3–4x under Miri)
Output on successVerbose dot progress or interleaved logsConcise pass/fail UI; passing tests stay quiet
Output on failureDebug logs can interleave with other testsPer-test captured output — logs belong to the failed test only
Environment safetyOne test can mutate env vars and affect anotherProcess isolation prevents cross-test interference
Fail fastStops within the current binaryStops the whole run faster across binaries
CI partitioningNo built-in partitioning--partition hash:1/2 splits runs across jobs

The process-per-test model is also why flaky-test retries are trustworthy: a retried test gets a fresh process, so leftover state from the failed attempt cannot pollute the retry.

How Do I Install Cargo Nextest?

Install Cargo Nextest with a prebuilt binary from the official site — it takes seconds and requires no compilation. The official installation page gives exact commands per platform; the table below copies the cargo nextest install routes verbatim. Note the source-install rule: cargo install cargo-nextest without --locked is not supported and will not work, and building from source needs Rust 1.91 or later.

RouteCommandNotes
Linux x86_64 (official prebuilt)
curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
Drops the binary into your cargo bin dir
Linux musl static
curl -LsSf https://get.nexte.st/latest/linux-musl | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
Fully static build for minimal images
macOS universal
curl -LsSf https://get.nexte.st/latest/mac | tar zxf - -C ${CARGO_HOME:-~/.cargo}/bin
Intel + Apple Silicon in one binary
Windows
winget install nextest.cargo-nextest
Official winget package
cargo-binstall
cargo binstall cargo-nextest --secure
Fast prebuilt install if you have binstall
Homebrew / Arch (community)
brew install cargo-nextest
pacman -S cargo-nextest
Listed in the official docs' community section
From source
cargo install cargo-nextest --locked
Requires Rust 1.91+; --locked is mandatory

Verify with cargo nextest --version — you should see cargo-nextest 0.9.150 or newer. In CI, the official docs recommend the taiki-e/install-action@nextest GitHub Action, which downloads prebuilt binaries into .cargo/bin without compiling anything.

How Do I Run My First Tests With Cargo Nextest?

Run your first tests by typing cargo nextest run in the root of any Rust project — nothing else is required. Nextest discovers your workspace, builds the test binaries if needed, and runs the full suite with its compact live UI. Follow this five-step arc for your first run:

  1. Check the binary: run cargo nextest --version and confirm it prints a version.
  2. Move to your project root: any Cargo workspace works — even one you have never tested before.
  3. Run the suite: type cargo nextest run and watch the summary line. Passing runs show a short green summary; failing runs print the failed tests' captured output only.
  4. List instead of running: cargo nextest list shows every discovered test without executing it — useful to verify filters later.
  5. Re-run failures only: use cargo nextest run --failed to iterate on just the broken tests.

Notice what you do not see: no wall of dots, no interleaved log spam from passing tests. Nextest captures each test's output and only shows it for failed or slow tests, which is why large CI logs become readable.

How Do Nextest Filter Strings and Filtersets Work?

Filter strings match tests by substring; filtersets (the -E flag) give you a Bazel-inspired query language for selecting tests by package, binary, platform, and more. This is the single lesson beginners skip and then regret. A filter string is the simple case — it is a substring match on the test name, not a regex. The Eclipse Ankaios project's docs show a real example: with a test named test podman::workload::container_create_success, they run cargo nextest run podman::workload to run every test whose name contains that substring.

Filtersets are the power tool. Prefix the -E (or --filterset) flag with a query expression. Here is one worked example of the nextest filterset syntax covering the most common need — running the deserialize-related tests of the serde package:

cargo nextest run -E 'package(serde) and test(deserialize)'

The official docs give two more canonical examples: cargo nextest run -E 'deps(my-crate)' runs all tests in a crate and its dependencies, and passing -E twice unions the sets — cargo nextest run -E 'test(my_test)' -E 'package(my-crate)' equals -E 'test(my_test) + package(my-crate)'. Two semantics matter here: multiple filtersets are unioned, but a filterset and a filter string are intersected — cargo nextest run -E 'package(foo)' -- test_bar test_baz runs tests in package foo matching either substring. The DSL predicates include test(), package(), deps(), rdeps(), binary_id(), kind(), binary(), platform(host|target), all(), none(), and default(), combined with &/and, |/+/or, not/!, and set difference with -. If you ever need the full grammar, cargo nextest help filterset prints it.

How Do I Handle Flaky Tests With Nextest?

Nextest retries flaky tests automatically once you set a retry count — and a test that passes on retry is explicitly marked flaky, not silently green. This is the nextest retry flaky workflow in three shapes. On the command line: cargo nextest run test_flaky_mod_2 --retries 2 (the official example) retries each failing test up to two more times. Via environment: NEXTEST_RETRIES does the same without flags. Via config, scoped to the tests that actually need it:

[[profile.default.overrides]]
filter = 'test(test_e2e)'
retries = 2

For tests that fail because of remote services rather than timing, add exponential backoff so retries do not hammer a struggling endpoint:

[[profile.default.overrides]]
filter = 'test(test_remote_api)'
retries = { backoff = "exponential", count = 2, delay = "5s", jitter = true }

Two policy details matter. By default, a flaky test still passes the run (exit code 0 if nothing else failed); to make flakiness fail the run, set --flaky-result fail or NEXTEST_FLAKY_RESULT=fail (available since 0.9.131). And for tests that are simply heavy — integration suites that must not run in parallel — assign them to a test group with test-group in overrides, then cap the group's parallelism with [test-groups.<name>] max-threads = 1 in your config.

How Do Nextest Profiles and Configuration Work?

Nextest config lives in .config/nextest.toml at your Cargo workspace root, and profiles let you keep a relaxed local setup and a strict CI setup in one file. Check the file into version control (--config-file overrides the path; personal preferences go in ~/.config/nextest/config.toml). Select a profile with -P or --profile, and note that custom profiles inherit from default unless you write inherits = "ci". The docs' recommended CI profile is minimal on purpose:

[profile.ci]
fail-fast = false

That one line tells CI to collect every failure instead of stopping at the first one, so you see the full damage in a single run. A second setting worth knowing is slow-timeout: slow-timeout = "60s" flags any test that runs longer than sixty seconds as slow (with terminate-after you can also kill it), which is how teams find the tests quietly doubling their suite time. Configuration follows a clear precedence — CLI args beat env vars like NEXTEST_RETRIES and NEXTEST_PROFILE, which beat per-test overrides, which beat profile config, which beats the inheritance chain ending at the built-in defaults. Per-test overrides also accept slow-timeout, leak-timeout, priority, flaky-result, test-group, and junit settings, so one file can describe your entire testing policy.

How Do I Add JUnit Reports to My Runs?

Enable nextest JUnit reporting purely through config — there is no --report CLI flag; Nextest writes the report automatically after each run once the path is set. Add this to your CI profile:

[profile.ci.junit]
path = "target/nextest/junit.xml"

With the path unset, JUnit reporting stays disabled; with it set, the XML lands in target/nextest/junit.xml after every run with that profile. GitHub Actions and GitLab both parse this format to render per-test results in the PR UI, which is why CI setups pair the ci profile with a junit path. The knobs around it: junit.report-name (default "nextest-run"), junit.store-success-output (default false — passing tests stay silent even in the report), junit.store-failure-output (default true), and junit.report-skipped (default "none", or "ignored"/"all"). If your pipeline consumes machine-readable results another way, note that an experimental libtest-compatible JSON output also exists.

How Do I Build Once and Run Tests Elsewhere?

Use cargo nextest archive to build your tests once, then cargo nextest run --archive-file on the target machine — the target does not even need Cargo installed. This is the escape hatch for slow CI builders, test machines, and environments where compiling Rust is impossible. Build the archive on your fast machine:

cargo nextest archive --workspace --all-features --archive-file my-archive.tar.zst

Then, on the target, with the same source revision checked out:

cargo nextest run --archive-file my-archive.tar.zst

Three rules make archiving work. First, the archive remembers the build options — do not repeat them on the run command. Second, the target machine must have Nextest installed but not Cargo; invoke it in the cargo-nextest nextest form there. Third, the same source revision must be checked out on both sides, or Nextest refuses to run. You can trim the archive with a filterset (cargo nextest archive --workspace -E 'rdeps(db-test-utils)' --archive-file archive.tar.zst), remap the workspace path on the target with --workspace-remap, and — new in 0.9.150 — widen compression with --zstd-long for faster archive creation. If your "elsewhere" is a container rather than a bare machine, the workflow composes naturally with Docker — see our Docker beginner guide for getting test-capable images running.

How Do I Use Cargo Nextest in CI?

Install Nextest as a prebuilt binary in your workflow, select the ci profile, and split large suites across jobs with --partition. This nextest ci setup mirrors the official recommendation. In GitHub Actions, the install step after your Rust toolchain step is:

- uses: taiki-e/install-action@nextest

Pin it when you want reproducible runs:

- uses: taiki-e/install-action@v2
  with:
    tool: nextest
    # tool: [email protected]      # version series
    # tool: [email protected]   # specific version

The test step is then just cargo nextest run -P ci, with CARGO_TERM_COLOR: always in env so colors survive the CI log. For suites too big for one runner, partition them: job one runs cargo nextest run --partition hash:1/2 and job two runs --partition hash:2/2 (count and slice partition styles exist too). Pair the CI profile with the JUnit path from the previous section so your platform renders per-test results in the PR. If GitHub Actions itself is new to you, our GitHub Actions beginner guide walks through workflow files from scratch, and if your runners are self-hosted on a VPS, see what VPS hosting is for sizing guidance.

What Should I Know About Doctests in Nextest?

Doctests are currently not supported by Nextest because of limitations in stable Rust — run them in a separate step with cargo test --doc. This is the one gap the official homepage states outright, and it catches beginners who switch fully to Nextest and then wonder why their doc examples stopped running. The rule is simple: unit and integration tests go through cargo nextest run; doctests go through cargo test --doc; in CI, run both steps. Note this once and move on — it is the only test category Nextest deliberately excludes.

What Are the Beginner Mistakes With Cargo Nextest?

Most Nextest mistakes come from carrying cargo test habits into a tool with different semantics. Here are the seven I see most often, all original observations from working with the tool's actual behavior:

MistakeWhat actually happensThe fix
cargo install cargo-nextest without --lockedThe install is not supported and failsAlways use cargo install cargo-nextest --locked, or a prebuilt binary
Expecting doctests to runDoc examples silently never execute under NextestAdd a separate cargo test --doc step
Looking for a --report flagIt does not exist — you search the docs in vainJUnit reports come only from the [profile.ci.junit] config section
Treating a filter string as a regextest_.* matches nothing — it is a substring matchUse substring text, or switch to -E filtersets for real queries
Assuming multiple -E flags intersectThey union — you get more tests, not fewerCombine with and inside one -E for intersection
Running an archive against a different revisionNextest refuses to run itCheck out the same source revision on the target first
Running CI with the default profileYou lose fail-fast=false, retries, and junit outputAlways run cargo nextest run -P ci in CI

Sources

  • Official Nextest homepage and quick start — https://nexte.st/ — "up to 3x faster than cargo test" claim, process-per-test model, taiki-e/install-action CI recommendation, doctest note.
  • Nextest changelog — https://nexte.st/changelog/ — cargo-nextest 0.9.150 released 2026-10-26; GHSA-vc25-qg58-w57c run-recording security fix; nextest-version = "0.9.150" pinning advice.
  • cargo-nextest 0.9.150 release — https://newreleases.io/project/github/nextest-rs/nextest/release/cargo-nextest-0.9.150 — published 2026-10-26T18:31:35Z.
  • Pre-built binaries installation — https://nexte.st/docs/installation/pre-built-binaries/ — verbatim install commands (curl tarballs per platform, winget, binstall, Homebrew/Arch community), taiki-e/install-action pinned variants.
  • Install from source — https://nexte.st/docs/installation/from-source/ — cargo install cargo-nextest --locked mandatory; plain install unsupported; Rust 1.91+ required.
  • Environment variables configuration — https://nexte.st/docs/configuration/env-vars/ — "Nextest runs each test in its own process... cargo test runs many tests in the same process."
  • Filtersets — https://nexte.st/docs/filtersets/ — -E 'deps(my-crate)', -E 'package(serde) and test(deserialize)', multiple -E union semantics, filterset-filter-string intersection.
  • Filterset DSL reference — https://nexte.st/docs/filtersets/reference/ — predicate and operator list.
  • Retries — https://nexte.st/docs/features/retries/ — --retries 2 example, flaky marking, --flaky-result fail since 0.9.131, exponential backoff config.
  • Per-test overrides — https://nexte.st/docs/configuration/per-test-overrides/ — test-group assignment, [test-groups.<name>] max-threads = 1, override-supported settings.
  • Configuration — https://nexte.st/docs/configuration/ — .config/nextest.toml location, -P/--profile, [profile.ci] fail-fast = false, slow-timeout = "60s", precedence chain.
  • Configuration reference — https://nexte.st/docs/configuration/reference/ — JUnit section defaults (report-name, store-success-output, store-failure-output, report-skipped).
  • Archiving — https://nexte.st/docs/ci-features/archiving/ — archive/run commands, same-revision requirement, no-Cargo-on-target rule, --zstd-long in 0.9.150.
  • Eclipse Ankaios unit-test docs — https://eclipse-ankaios.github.io/ankaios/0.3/development/run-unit-tests/ — real filter-string example (cargo nextest run podman::workload), per-test output capture behavior.
  • cargo-mutants Nextest page — https://mutants.rs/nextest.html — confirms doctests are not run by Nextest.
  • Rust Project Primer (third-party) — "drop-in replacement for cargo test that uses a process-per-test execution model"; JUnit report written after each run once configured.

Frequently Asked Questions

Is cargo nextest a drop-in replacement for cargo test?

Yes, for unit and integration tests. Nextest uses the test binaries Cargo compiles and adds cargo test -- argument pass-through, so existing projects switch by typing cargo nextest run instead of cargo test. The one exception is doctests, which need a separate cargo test --doc step.

Why is cargo nextest faster than cargo test?

Because it schedules tests across all test binaries in parallel instead of running binaries serially, and process-per-test isolation lets it retire finished tests immediately. The official site claims up to 3x faster than cargo test, and the Miri integration page reports 3–4x under Miri. Your mileage varies with core count and test mix.

How do I run only one test file or module with nextest?

Use a filter string — a substring of the test name: cargo nextest run my_module::. For precise selection across packages, use a filterset: cargo nextest run -E 'package(my-crate) and test(my_test)'. List first with cargo nextest list to confirm your filter matches.

Does cargo nextest support JUnit XML reports?

Yes, through config only. Add [profile.ci.junit] with path = "target/nextest/junit.xml" in .config/nextest.toml; the report is written automatically after each run with that profile. GitHub Actions and GitLab parse it to show per-test results in pull requests.

What does "flaky" mean in nextest output?

A test marked flaky failed its first attempt and passed during a retry, so it passes the run by default. If you want flaky tests to fail the build instead, set --flaky-result fail or NEXTEST_FLAKY_RESULT=fail (0.9.131+).

Featured on Twelve Tools Launch Llama Tools Launch your MCP