Self-hosted service
tqdm/tqdm avatar
tqdm/tqdm

tqdm: wrapping Python loops and shell pipes in a progress meter

:zap: A Fast, Extensible Progress Bar for Python and CLI

31,337 stars1,513 forksPythonNOASSERTION

At a glance

What is it?
tqdm is a single-purpose progress bar library for Python and the command line. The README claims roughly 60ns of overhead per iteration, and the design decisions that produce that number also define where the tool stops being the right choice.
Who is it for?
Adopt tqdm if you have a Python loop or a shell pipeline whose runtime you cannot see and you want a one-line change to fix that. Do not adopt it if you need a persistent dashboard, structured metrics, or progress reporting from a process that has no writable terminal, since tqdm writes to stderr by design.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

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

DEEP OPEN-SOURCE ANALYSIS

The problem tqdm solves is silence, not measurement

A long-running loop or pipeline gives you nothing until it finishes. tqdm's answer is to wrap the iterable in place, so the loop body does not change at all. The README example is three lines: import tqdm, wrap the range, run. The meter renders to the terminal while the loop does its work. The audience is anyone who runs a script interactively and wants to know whether it is 5 percent or 95 percent done, plus anyone building a pipeline where a stage takes minutes and produces no output of its own. The library also covers the case where the total is unknown, since tqdm can run without a total and fall back to counting iterations. The project describes itself as dependency-free, requiring only Python and a terminal that honours carriage return and line feed. That constraint explains a lot of the design: no curses, no external rendering library, nothing to install alongside it.

Iterable wrapping, manual updates, and the module form are three different mechanisms

The iterable form is the simplest. tqdm(iterable) returns a wrapper that yields the same items and updates the display as it goes. trange(N) is a shortcut for tqdm(range(N)). When you need to change the label mid-loop, the README shows instantiating the bar first, iterating over it, and calling pbar.set_description inside the body. The manual form drops the iterable entirely: you create tqdm(total=100) and call pbar.update(10) yourself, which suits loops whose unit of work is not one item. The README notes that if total or an iterable with len() is supplied, predictive stats are shown, which is the mechanism behind the remaining-time estimate. The with statement form closes the bar automatically; without it you must call close() or delete the object, and the README says so explicitly. The third mechanism is the module form: inserting tqdm or python -m tqdm between pipes passes stdin through to stdout while printing progress to stderr. That separation of streams is what makes it composable, and it is also the reason the bar does not corrupt piped data.

Installing it, and the flags that matter in a pipeline

The stable release is pip install tqdm. Alternatives listed in the README include conda install -c conda-forge tqdm, snap install tqdm with candidate and edge channels, and docker pull tqdm/tqdm followed by docker run -i --rm tqdm/tqdm --help. The README states that snap binaries are purely for CLI use and are not importable, and that they set up bash tab-completion automatically. A pre-release branch can be installed with pip install "git+https://github.com/tqdm/tqdm.git@devel#egg=tqdm". On the command line, the flags shown in the README are --bytes, --total, --unit, --unit_scale, --desc and --position. The --total flag is what enables a percentage and an ETA; without it the module counts items but has no denominator. --position matters when you stack two bars in one pipeline, which the README demonstrates by running tar through one tqdm instance, gzip, and then a second tqdm instance with --position 1. --bytes switches the unit to bytes and pairs with --total set from du -sb.

The 60ns figure and what it does not cover

The README states overhead of about 60ns per iteration, 80ns with tqdm.gui, and says this is unit tested against performance regression. It compares this to ProgressBar at 800ns per iteration. Those numbers come from the project's own material and depend on the workload, the terminal, and the update frequency, so treat them as a starting point rather than a guarantee for your loop. The library skips unnecessary iteration displays, which is the mechanism that keeps the cost down when the loop is fast. The practical consequence is that a loop doing microseconds of real work per item will see a visible slowdown, while a loop doing milliseconds of work will not. The README's own pipe example shows the effect: the timing block goes from 3.458s to 3.585s when tqdm is inserted, with user time rising from 0.274s to 0.862s. That is a real, published measurement on a find-and-cat workload, and it is the honest way to read the 60ns claim.

Where tqdm is the wrong tool

tqdm writes to stderr and redraws a single line. That makes it a poor fit for anything that needs a durable record: there is no structured event stream, no way to query progress after the fact, and no history beyond what scrolls past. It is also a poor fit for non-interactive environments. In a CI log, a cron job, or a container whose output is captured to a file, the carriage-return redraw becomes either a wall of partial lines or nothing useful. The README's own framing supports this: it requires an environment supporting carriage return and line feed control characters, which a log file is not. A second limitation is nesting. The README handles multiple bars through --position on the command line, but the Python API does not offer the same first-class story for many concurrent bars, and the documentation does not present one. A third is distributed work: tqdm tracks progress inside one process, so a job spread across workers needs aggregation that the library does not provide.

The alternative worth comparing is ProgressBar, and the difference is architectural

The README names python-progressbar directly and gives the comparative figure: 800ns per iteration against tqdm's 60ns. The difference is not only speed. tqdm ships with a CLI module, so the same tool covers a Python loop and a shell pipe, and it has no dependencies at all, not even curses. ProgressBar is a Python library for Python loops; it does not give you the pipe form, and the README does not present it as doing so. That distinction matters if your work spans both worlds, because adopting tqdm means one mental model for both. If your work is entirely inside a Python process and you want a widget-based or terminal-UI style display, a different class of tool is the comparison, not ProgressBar. The README also lists tqdm.gui as a variant with higher overhead at 80ns, which is the project's own acknowledgement that the rendering backend is a tunable cost.

Maintenance, release cadence, and the licence question

The repository is not archived, and the release list shows three stable releases in the space of a month: v4.69.0 on 2026-07-17, v4.69.1 on 2026-07-24, and v4.70.0 on 2026-07-27. That cadence means pinning matters. For a library this widely depended on, an unpinned install can pull a new minor version into a build without warning, and the changelog is distributed across GitHub Releases, a wiki page, and the project website rather than a single file in the repository. Upgrading therefore requires reading release notes in more than one place. On licensing, the repository metadata reports the licence as NOASSERTION. That is not a licence identifier; it means the automated classifier could not map the repository's licence file to a known SPDX identifier. The README carries a licence badge but the cleaned text does not name the licence. Anyone embedding tqdm in a distributed product should read the LICENSE file in the repository and confirm the terms with their own counsel rather than relying on the metadata field.

Who should install it, and what to check first

Install tqdm when you have a Python loop over an iterable with a known or countable length and you want visibility without restructuring the loop. Install it when you have a shell pipeline and want a byte counter with an ETA, in which case the pattern is tqdm --bytes --total "$BYTES" inserted between stages. Skip it when the output goes to a log aggregator rather than a terminal, when you need machine-readable progress events, or when the loop body is faster than the bar's own update cost. Before adopting, run the loop once with and once without tqdm and compare wall time; the README's pipe example shows a 0.127s difference on a 3.5s job, and your ratio will differ. Then open the LICENSE file and confirm the terms for the version you pinned, because the metadata says NOASSERTION and that is the only signal the repository gives.

Editorial conclusion

Adopt tqdm if you have a Python loop or a shell pipeline whose runtime you cannot see and you want a one-line change to fix that. Do not adopt it if you need a persistent dashboard, structured metrics, or progress reporting from a process that has no writable terminal, since tqdm writes to stderr by design. Before committing, verify two things against your own environment: the per-iteration overhead on your actual workload rather than the README figure, and the licence terms of the exact release you install, because the repository metadata reports the licence as NOASSERTION and that is not the same as a confirmed OSI identifier.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. tqdm/tqdm on GitHub
Community notes

Community notes