6 releases

0.3.0 May 18, 2022
0.2.2 Feb 21, 2022
0.2.1 Jun 12, 2021
0.2.0 May 28, 2021
0.1.1 Dec 20, 2020

#365 in Command-line interface

Download history 42/week @ 2023-12-07 51/week @ 2023-12-14 43/week @ 2023-12-21 19/week @ 2023-12-28 46/week @ 2024-01-04 60/week @ 2024-01-11 53/week @ 2024-01-18 36/week @ 2024-01-25 22/week @ 2024-02-01 43/week @ 2024-02-08 65/week @ 2024-02-15 78/week @ 2024-02-22 72/week @ 2024-02-29 84/week @ 2024-03-07 98/week @ 2024-03-14 93/week @ 2024-03-21

360 downloads per month
Used in 11 crates (7 directly)

MIT license

182 lines


Workflow Status

Simple concurrent progress bars.


  • Intuitive API.
  • First-class support for rayon, etc.
  • Efficient, allocation-free redraws.
  • Addition of new subbars on-the-fly.
  • Single-threaded multi-bars.
  • Light-weight, only a single dependency.


linya is designed around the multi-bar case, and unlike other progress bar libraries, has no separate type for individual bars. Instead, we use the Progress type, a "bar coordinator".

Multi Bars

To mutably access a Progress across threads it must be wrapped in the usual concurrent sharing types. With rayon specifically, only Mutex is necessary:

use std::sync::Mutex;
use linya::{Bar, Progress};
use rayon::prelude::*;

let progress = Mutex::new(Progress::new());

// `into_par_iter()` is from `rayon`, and lets us parallelize some
// operation over a collection "for free".
(0..10).into_par_iter().for_each(|n| {
  let bar: Bar = progress.lock().unwrap().bar(50, format!("Downloading {}", n));

  // ... Your logic ...

  // Increment the bar and draw it immediately.
  // This is likely called in some inner loop or other closure.
  progress.lock().unwrap().inc_and_draw(&bar, 10);

Notice that new bars are added on-the-fly from within forked threads. We call Progress::bar to obtain a new "bar handle", and then pass that handle back to the parent Progress when incrementing/drawing.

See Progress::inc_and_draw and Progress::set_and_draw to advance and render the bars.

Single Bars

Progress can also be used in a single-threaded context for individual bars. The usage is the same, except that no locking is required:

use linya::{Bar, Progress};

let mut progress = Progress::new();
let bar: Bar = progress.bar(50, "Downloading");

// Use in a loop, etc.
progress.set_and_draw(&bar, 10);

In this way, you could even have multi-bars in a single-threaded context.


Some of the points below may be fixed in future releases.

  • Your terminal must support ANSI codes.
  • No dedicated render thread, to keep usage simple.
  • No bar templating, to avoid dependencies.
  • No other bar styling (yet).
  • No "rates", since rerenders are not time-based.
  • No bar clearing after completion.
  • No spinners, also due to no sense of time.
  • No dynamic resizing of bars if window size changes.

If you need more customizable progress bars and are willing to accept heavier dependencies, please consider indicatif.

Note also that using more than one Progress at the same time leads to unspecified behaviour.


Linya is the Quenya word for "pool", as in a beautiful mountain pool.