CLI tool
console-rs/indicatif avatar
console-rs/indicatif

indicatif: progress bars for Rust CLIs, and what its changelog reveals

A command line progress reporting library for Rust

5,224 stars293 forksRustMIT

At a glance

What is it?
A MIT licensed Rust crate for drawing progress bars and spinners, whose 0.18.x release notes read as a catalogue of everything terminals do to you.
Who is it for?
indicatif is small, dependency-light and past the point where it needs arguing for, but reading its release notes tells you something the README does not: the hard part is not drawing a bar, it is drawing one correctly on a dumb terminal, a CI log, a wide-character locale and a redirected stdout at the same time.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the crate provides, and what it admits it does not

The README describes indicatif as a Rust library for indicating progress in command line applications, then makes an unusually candid admission: it currently primarily provides progress bars and spinners as well as basic color support, but there are bigger plans for the future.

That sentence matters because it tells you the scope. This is a drawing library, not a task framework. It does not spawn work, it does not know what you are iterating over, and it does not manage concurrency. You call the increment method when a unit of work completes and the crate decides how to repaint. Everything else about your progress reporting, including what counts as a unit and what the message says, stays with you.

The examples section points at four programs under `examples/`: `yarnish.rs`, `download.rs`, `multi.rs` and `single.rs`. That is a small and honest selection. `single.rs` is the one-bar case, `multi.rs` shows several bars stacked and managed together, `download.rs` is the transfer-shaped case with a byte count and a rate, and `varnish.rs` is the awkward one, a cache-like workload with irregular step sizes.

The repository itself is lean. The tree holds `src/`, `tests/`, `examples/`, `screenshots/`, a committed `Cargo.lock`, a `deny.toml` for cargo-deny, and `Cargo.toml`. A `deny.toml` in a library this size says the maintainers care about dependency advisories and license hygiene, which is a reasonable thing to want in something 5,200 other projects pull in. The last push was 2026-09-22 and the crate has 92 open issues.

Feature flags that describe the terminal problem

The most informative part of `Cargo.toml` is the features table, because each flag maps to a class of terminal problem rather than to a function:

toml
[features]
default = ["unicode-width", "wasmbind"]
unicode-width = ["dep:unicode-width", "console/unicode-width"]
improved_unicode = ["unicode-segmentation", "unicode-width"]
in_memory = ["vt100"]
futures = ["dep:futures-core"]
wasmbind = ["dep:web-time"]

`unicode-width` is on by default and is effectively not optional. Correct column arithmetic is the entire ballgame for a progress bar: if your width function disagrees with the terminal's own notion of a character, bars end at column 80 in an 82 column window or wrap mid-line. `improved_unicode` goes further and pulls in `unicode-segmentation`, which lets the crate segment grapheme clusters rather than code points, so a combining character or an emoji occupies the columns it actually occupies.

`in_memory` is the flag to notice. It enables `vt100`, an in-process terminal emulator, and that means the drawing logic can be tested against a simulated terminal instead of a real one. For a library whose entire job is producing a byte stream that must look right, that is the difference between having tests and having confidence.

`futures` exposes the `futures-core` dependency for async use, and `wasmbind` pulls in `web-time` on wasm32, which is why a progress bar that works on Windows and Linux can also compile to a browser. The minimum supported Rust version is stated as 1.85 on edition 2021, which is a recent floor and worth checking against your toolchain before you pin the dependency.

The 0.18.x changelog as a list of terminal failure modes

The release notes are short, a sign of a well-run project, but each entry is a bug you would otherwise have to rediscover. Version 0.18.6, published 2026-07-01, is a single fix: correctly detecting a dumb terminal on Windows. Version 0.18.5, published two days earlier on 2026-06-29, is the interesting one.

Four entries from 0.18.5 concern drawing rather than logic. One clears the rest of the line after drawing to the terminal, which is the fix for a bar shorter than the previous one leaving fragments of the old bar behind. One fixes the stderr detection method for `MultiProgress`, so code deciding where to print can trust the answer when several bars are in play. One fixes height and filler when text is wrapped in the middle of wide characters. One fixes `HumanFloatCount` in two separate ways: a stray comma appearing after the minus sign for negative values, and the fractional part being dropped entirely.

Two more entries concern the environment rather than the drawing. One makes the crate respect `NO_COLOR` and `TERM=dumb`, which is correct behaviour and the kind of thing usually missing. One adds a refresh rate warning for the term-like draw target, so a caller who asks for a term-like target without giving a rate gets told rather than silently repainting too often.

Version 0.18.4, published 2026-02-14, has a draft heuristic for `hold_max`, which appears to be about holding a maximum width estimate rather than recalculating it every frame, plus a fix for duration display after a bar finishes. Read together, the three releases describe a library that has absorbed a year of small, specific, unrewarding correctness work, which is the honest characterisation of terminal UI code.

The dependency list explains how drawing happens

Indicatif delegates the hard terminal work, and the dependencies show exactly what it delegates:

toml
console = { version = "0.16.4", default-features = false, features = ["ansi-parsing", "std"] }
unit-prefix = "0.5.1"
portable-atomic = "1.12.0"
rayon = { version = "1.1", optional = true }
tokio = { version = "1", optional = true, features = ["io-util"] }
vt100 = { version = "0.16.1", optional = true }

`console`, from the same organisation, handles the low level: terminal detection, ANSI parsing, and writing styled text. Only the `ansi-parsing` and `std` features are requested, with default features off, which keeps the dependency surface small. Terminal detection is where `TERM=dumb` and the Windows dumb-terminal fix from the changelog get their behaviour, and it explains why that class of bug existed at all.

`unit-prefix` is the dependency you would not have predicted. It formats numbers with SI or binary unit prefixes, which is what makes the download example read as a human-readable transfer count rather than raw bytes. Doing that correctly, including pluralization and the boundary between kilobytes and kibibytes, is fiddly enough that factoring it out makes sense.

`portable-atomic` is there for correctness on architectures where atomics are not universally lock-free. That is the sort of dependency that appears without discussion and prevents a class of problem on obscure targets.

The optional `rayon` and `tokio` entries are worth separating carefully. `futures` for async iteration is a supported path. The `tokio` dependency is enabled with only `io-util`, and `rayon` appears in the dependency list without a dedicated feature name in the table, so treat both as narrower than seeing them listed might suggest. The real integration surface for most users is the `log` and `tracing` bridges, which are separate crates.

Two integration crates that solve one specific fight

The integrations section of the README is short and names two crates, both solving the same underlying problem.

`indicatif-log-bridge` integrates with the `log` crate so log output does not collide with an active progress bar. `tracing-indicatif` does more for the `tracing` crate: it manages progress bars automatically for active tracing spans, and it keeps tracing log events from interfering with bars that are currently drawing.

The reason this problem needs a dedicated crate is that both libraries want to own the terminal. A progress bar repaints continuously to show motion, and a logger writes discrete lines. If both write to the same stream, the bar's cursor restoration fights the log line and you get the familiar mess of a mangled line with a bar fragment stuck in the middle of it. Solving it properly means suspending the bar, writing the log line, and resuming the bar, and both of these crates do that.

For a `tracing` user, the span-driven approach is the more interesting one, because it means the progress bar is a consequence of your instrumentation rather than a separate thing you have to remember to update. Instrument an async span and get a bar for it. The trade-off is that you are expressing progress through span entry and exit, a different mental model from incrementing a counter yourself.

One packaging note: the crate excludes its screenshots from the published package while keeping them in the repository, since the manifest sets an exclude entry for the screenshots directory and the tree still has one. The README's examples are animated gifs, and the 0.18.5 notes mention dropping screenshots from the package.

When to use it, when to write the bytes yourself

The case for indicatif is a long operation with a countable unit of work. A download, a file conversion, a migration, a build step iterating over a known collection. In those cases the bar does something real: it reports progress, and for transfers it also reports rate and estimated time remaining, which is the information people actually want from a slow command.

The case against is output that is being piped. A progress bar written to stdout corrupts a pipeline for the same reason it corrupts a file. Indicatif handles this, because it detects that a stream is not a terminal and knows to draw nothing, but that is a behaviour to verify for your own invocation rather than assume, particularly on Windows where the terminal detection needed a fix as recently as 0.18.6.

There is a size question too. Indicatif plus `console` is not nothing to add to a small binary, and for a tool with one progress phase a hand-rolled counter on stderr is twenty lines and no dependencies. The library earns its weight when you need multiple coordinated bars, ETA calculation, rate formatting, unicode width handling and a tested escape sequence for suspension, because each of those is a small decision somebody has already made badly at least once.

The documentation lives on docs.rs rather than in this repository, and the README is candid about it, pointing at the docs.rs badge as the first item in its badge row. Progress style templates, tick and humanized duration strings, and the `MultiProgress` semantics are all documented there, along with the common bugs that the 0.18.5 release notes specifically started writing down.

Editorial conclusion

indicatif is small, dependency-light and past the point where it needs arguing for, but reading its release notes tells you something the README does not: the hard part is not drawing a bar, it is drawing one correctly on a dumb terminal, a CI log, a wide-character locale and a redirected stdout at the same time. The `in_memory` feature backed by `vt100` is the part to borrow conceptually even if you never use the crate, because it is how you test terminal output without a terminal. Pick it when your program has a long, measurable operation worth reporting, and write the byte stream yourself when your output is meant to be piped and a bar would be noise. Either way `ProgressStyle` templates and `MultiProgress` are where the real capability sits, and both are documented on docs.rs rather than in this README.

Frequently asked questions

What is indicatif used for in Rust?

Drawing progress bars and spinners in a command line program. You call it when a unit of work completes and the crate handles repainting, width arithmetic, rate and estimated duration formatting. It does not manage the work itself or spawn concurrency.

How do I stop indicatif from interfering with log output?

Use one of the two integration crates. `indicatif-log-bridge` integrates with the `log` crate, and `tracing-indicatif` integrates with `tracing`, managing bars for active spans and keeping log events from disturbing bars that are drawing.

How does indicatif test terminal output?

Through the optional `in_memory` feature, which enables the `vt100` dependency, an in-process terminal emulator. That lets the drawing logic be exercised against a simulated terminal rather than requiring a real one, which is the practical way to test a byte stream meant to look right.

Does indicatif respect NO_COLOR and dumb terminals?

Yes, as of version 0.18.5, published 2026-06-29, which added respect for the `NO_COLOR` and `TERM=dumb` environment variables. Version 0.18.6 followed with a fix for correctly detecting a dumb terminal on Windows specifically.

What Rust version does indicatif require?

The manifest states a minimum of Rust 1.85 on edition 2021, and the current version is 0.18.6, published 2026-07-01. The license is MIT and the package is published on crates.io.

Official sources

  1. console-rs/indicatif on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/console-rs-indicatif.svg)](https://hysenlabs.com/projects/console-rs-indicatif)