Skip to content
jenkin edited this page May 28, 2026 · 2 revisions

FAQ

Why does cargo-fresh exist if cargo-update is right there?

Short answer: different design priorities. The README has a feature-by-feature comparison table. Both projects are healthy; pick whichever fits.

Long answer: cargo-update runs cargo search per package as a subprocess; cargo-fresh hits the crates.io sparse index directly with one shared HTTPS client. For ~20 packages, that's the difference between ~20s and ~3s. cargo-fresh also handles git+URL and path+DIR sources natively, has glob filtering, and ships a stable --format=json schema for CI scripts.

Does cargo-fresh actually run cargo install?

Sometimes. cargo-fresh's job is deciding what to update and picking the right install path. For each selected package:

  • For crates.io packages with a GitHub release, cargo-fresh's in-process downloader resolves the release asset via the GitHub Releases API (HEAD-probe as fallback), streams it, verifies the optional .sha256 sidecar, and atomically renames it into ~/.cargo/bin. cargo install is not invoked in this path.
  • For everything else — non-GitHub crates, packages without prebuilt assets, git+URL sources, path+DIR sources — cargo-fresh shells out to cargo install --force <pkg> (with --git URL [--rev REV] or --path DIR as appropriate).

The downloader path is unique to cargo-fresh; the cargo install path uses cargo's normal verification.

Is the first run slow?

Maybe. cargo install --list populates a one-shot cache, so checking 20 packages spawns one cargo subprocess, not twenty. The sparse index requests run 16 in parallel with a shared HTTPS connection pool — first request might pay TLS handshake cost (~200ms), the rest reuse it.

If the first run takes more than ~10s, the usual suspects are:

  • cargo search fallback kicking in because sparse index can't reach index.crates.io — try --no-cargo-search-fallback --verbose to see
  • Network proxy not configured — set HTTPS_PROXY
  • DNS resolution slow — independent of cargo-fresh

What happens if a version gets yanked?

cargo-fresh skips yanked versions when parsing the sparse index response. If 0.5.0 is yanked and 0.4.9 is the latest non-yanked, cargo-fresh treats 0.4.9 as latest.

If you already have a yanked version installed (because you installed it before the yank), cargo-fresh's semver comparison uses latest > current — so a yank rollback (current > latest) does not trigger a fake "needs update" message. You stay where you are unless someone publishes a newer non-yanked version.

Does cargo-fresh upgrade itself?

If you ran cargo install cargo-fresh, then yes — cargo-fresh appears in cargo install --list and gets checked alongside everything else. You'll see Updating cargo-fresh 0.11.0 -> 0.12.0 like any other package.

The "running binary updates itself" path works on Unix (the old executable is unlinked but the running process keeps it open via inode). On Windows it can fail because the running .exe is locked — bump cargo-fresh manually with cargo install --force cargo-fresh from outside cargo-fresh itself.

Does cargo-fresh use cargo-binstall?

No — as of 0.11.0, cargo-fresh has its own in-process binary downloader (HTTP streaming + sha256 verify + atomic install), and 0.12.0 removed every code path that touched cargo binstall. Old releases relied on cargo binstall, but the current version does not invoke, install, or check for it.

If you want the fast path: nothing to install — it's built in. cargo-fresh resolves the GitHub Release asset via the GitHub Releases API (set GITHUB_TOKEN to raise the 60/hr anonymous quota to 5000/hr) and falls back to plain cargo install for packages that don't have a matching prebuilt binary.

--dry-run never installs anything regardless.

What's the difference between --batch and --no-interactive?

Flag Behavior
--batch Auto-select all update candidates, then install them
--no-interactive Show candidates but don't prompt, don't install anything; exit 1 if updates exist

Use --batch when you trust cargo-fresh to install whatever it finds (CI auto-upgrade jobs). Use --no-interactive for "tell me what's stale" gating without side effects.

How does -j N / --jobs N work?

cargo-fresh runs up to N package updates concurrently via tokio::JoinSet. Default is 4 — downloads are network-bound and the inner HEAD-probe pool already caps connection fan-out, so 4 balances throughput against GitHub-CDN friendliness. -j 0 means unlimited (one task per selected package); -j 1 restores the 0.11.x serial behavior.

Update rows render via MultiProgress and are pre-registered in input order, so the visual layout stays stable even when packages finish out of order. The end-of-run summary is also re-sorted into input order. Packages that fall back to cargo install naturally serialize on cargo's $CARGO_HOME lock regardless of -j.

How does cargo-fresh know about my mirror?

cargo-fresh reads $CARGO_HOME/config.toml looking for:

[source.crates-io]
replace-with = "my-mirror"

[source.my-mirror]
registry = "sparse+https://my-mirror.example.com/index/"

Only the sparse+URL prefix is honored. If your mirror is git-style (https://... without the sparse+ prefix), cargo-fresh falls back to cargo search for that package.

To override per-invocation: --registry-url https://my-mirror.example.com/index/.

What does [unknown source] mean?

You'll see this in the candidate list:

   Skip whatever-tool 1.0.0 [unknown source]

cargo-fresh got something in cargo install --list that isn't registry+..., git+..., or path+.... Rather than guess what to do (and potentially install the wrong thing from crates.io), cargo-fresh skips the package and tells you. If you're seeing this on a common source prefix, please file an issue — parse_source might need to handle one more case.

Does cargo-fresh work offline?

Partial. cargo install --list works offline (reads ~/.cargo/.crates.toml). The version check needs network — sparse index requests will fail and fall back to cargo search, which also needs network. So: no, not really, unless you only want the discovery phase.

Can I configure default flags?

Not today. ROADMAP P2-4 plans a config file at ~/.config/cargo-fresh/config.toml. For now, shell aliases are the workaround:

alias cf "cargo fresh --filter cargo-* --exclude '*-test'"

Why are some status verbs colored differently?

Color carries semantics:

  • Green — success or a normal step (Checking, Found, Updated, Finished)
  • Yellow — warning or non-fatal note (Note, Fallback, Skip, Slow, Aborted)
  • Red — failure (Failed, Finished when something errored)
  • Dim — secondary info you can usually ignore (Fresh, Package N/M, Hint, Check, Latest)

The status verb wording is not part of the 1.0 stability contract — anchor your scripts on --format=json or exit codes, not on text matching.

How do I get terminal completion?

cargo fresh completion bash > ~/.local/share/bash-completion/completions/cargo-fresh
# or for zsh / fish / powershell / elvish / nushell

These scripts are generated from the real CLI definition (via clap's CommandFactory), so they always match what --help shows.

For the cargo fresh subcommand form to autocomplete properly:

cargo fresh completion bash --cargo-fresh > ~/.local/share/bash-completion/completions/cargo-fresh

Where does cargo-fresh log to?

By default, nothing — only stdout/stderr. --verbose prints per-package check progress to stderr via status_dim. There's no log file. ROADMAP P2-7 plans tracing + RUST_LOG support.

What's the contract for 1.0?

See README → Stability Guarantees. Short version:

  • Stable: exit codes (0 / 1 / 2 / 130), --format=json schema_version=2 field shape (0.12.0 bumped from 1 — final pre-1.0 break), CLI flag inventory
  • Not stable: status verb wording, color, locale strings

Anchor scripts on the first three; never on the last three.