mpb

A concurrency-safe Go library for rendering multiple progress bars in terminal applications, with dynamic totals and pluggable decorators.

Library
Go
vv8.16.1
2,509stars
Unlicense

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
85/100Excellent
Development Activity96
Maintenance96
Community48
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
81/100Excellent
Architecture82
Code Quality90
Innovation78
Learning Curve75

mpb renders one or more progress bars in Go command-line applications without requiring callers to manage locks themselves. Each Progress container and each Bar owns a private goroutine that only ever mutates its own state in response to closures sent over a channel, so adding, removing, or updating bars from multiple goroutines is safe by construction rather than by convention.

Bars support dynamic totals that can change mid-render, queued bars that start only after another completes, and a decorator system (decor package) for composing elapsed time, EWMA-smoothed ETA, percentage, and byte-count displays on either side of a bar. The library ships as a dependency-light, dependency-injected set of functional options (ContainerOption, BarOption), making it straightforward to drop into CLI tools that need multi-bar progress reporting for parallel downloads, builds, or batch jobs.

What You Get

  • Concurrency-safe multi-bar rendering — each container and bar runs its own goroutine, reachable only via channel-sent state-mutation closures
  • Dynamic totals — a bar’s total can be changed after creation, useful when work size isn’t known upfront
  • Composable decorators — prepend/append elapsed time, EWMA-based ETA, percentage, and byte-count displays from the decor subpackage
  • Queued and dependent bars — a bar can be configured to start only once another bar completes, via BarQueueAfter
  • Graceful cancellation — the whole render process can be cancelled via context, unblocking any goroutines waiting on Wait()
  • io.Reader/io.Writer/io.ReadSeeker proxies — wrap an existing reader or writer so its progress is tracked automatically as bytes flow through it

Common Use Cases

  • Showing per-file progress bars while downloading multiple files concurrently
  • Tracking progress of parallel worker goroutines processing a batch job
  • Wrapping an HTTP response body or file reader so upload/download progress is reported without manual byte counting
  • Building CLI tools (package managers, build tools, backup utilities) that need multiple simultaneous progress indicators
  • Chaining dependent long-running steps where one progress bar should only start after a prior one finishes

Under The Hood

Architecture mpb uses a channel/goroutine-driven actor-like model: Progress.serve runs a monitor goroutine that owns a pState (holding a priority queue of *Bar via heapManager), and all mutation happens by sending closures over an operateState chan func(*pState) — communicating by sharing memory via channels rather than locks. Each Bar similarly owns a private goroutine reachable only via its own operateState chan func(*bState), so bar-local state (decorators, filler, counters) is never touched concurrently from outside. Rendering is decoupled from mutation: a ticker-driven renderReq channel triggers periodic frame draws that flow through frameCh to a cupwriter-backed ConsoleWriter for ANSI redraw. The core abstraction — state mutation as a function value sent over a channel — is pervasive; changing it would ripple through nearly every public method across bar.go, progress.go, and heap_manager.go. Options follow the standard functional-options pattern (ContainerOption, BarOption).

Tech Stack Built for Go 1.25 with a deliberately small dependency set: github.com/VividCortex/ewma for EWMA-smoothed ETA calculation, github.com/acarl005/stripansi and github.com/mattn/go-runewidth for terminal-width-aware string measurement that accounts for ANSI codes and wide runes, and github.com/vbauerster/cupwriter for cursor-aware terminal redraws. Indirect tooling includes golang.org/x/tools/cmd/stringer, invoked via go:generate to produce stringer methods for enum-like types (e.g. byte-size units in decor/). CI runs the test suite across stable and oldstable Go on Ubuntu, macOS, and Windows, with a separate golangci-lint workflow.

Code Quality The repository carries an extensive test suite alongside its implementation files — bar_test.go, progress_test.go, a substantial draw_test.go, decorators_test.go, and proxy-reader/writer/read-seeker tests, plus dedicated tests under decor/ and internal/ for ETA, percentage, and size-formatting logic, with a benchmark file (barbench_test.go) and godoc-verified example_test.go. Error handling favors explicit, typed errors (a generic ErrDone[T] for use-after-Wait() misuse) and context-based cancellation over swallowed errors. Naming is consistent and idiomatic Go throughout, and golangci-lint runs in CI on every push and pull request.

API Design The public API is a small, composable functional-options surface: mpb.New(...ContainerOption) for the container and p.AddBar(total, ...BarOption)/p.New(...) for bars, with decorators supplied separately via mpb.PrependDecorators/AppendDecorators from the decor subpackage. This keeps a single-bar quick start to a handful of lines while still exposing width syncing, dynamic totals, and queueing for advanced cases. Every exported type and function carries a godoc comment, and the _examples/ directory has 20+ runnable, narrowly-scoped programs (single bar, multiple bars, dynamic total, queued bar, I/O proxying, spinners) that double as the primary onboarding path alongside the README.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search