# vbauerster/mpb: multi progress bar for Go CLI applications

> mpb renders several progress bars at once in a Go terminal program, with decorators for elapsed time, ETA and byte counts. It is a library, not a binary, and it takes over the terminal while it runs.

**vbauerster/mpb** — multi progress bar for Go cli applications

- Repository: https://github.com/vbauerster/mpb
- Stars: 2,512 · Forks: 132
- Language: Go
- License: Unlicense
- Published: 2026-08-04 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/vbauerster-mpb

## What mpb solves, and who it is for

A Go CLI that downloads ten files in parallel has a display problem. Ten goroutines each want to report progress, and a naive fmt.Printf from each one interleaves into unreadable output. mpb is a library that owns that output instead: the README describes it as "a Go lib for rendering progress bars in terminal applications", and the first listed feature is multiple bars. The audience is Go developers writing command line tools, not people looking for a standalone progress binary. Nothing in the repository ships an executable entry point; the top level is package files (bar.go, progress.go, proxyreader.go, console_writer.go) plus a decor/ subpackage and an _examples/ directory of runnable programs. The dependency list in go.mod is small and terminal-focused: ewma for the ETA estimate, go-runewidth for character widths, stripansi, and cupwriter. If you have a single long operation and want one bar, this is more machinery than the job needs.

## The container, the bars, and the draw loop

The architecture is a container that renders many bars. mpb.New() builds the container and accepts options; p.New(total, ...) or p.AddBar(total, ...) adds a bar to it. Each bar carries its own fill style and its own decorator lists, split into prepended and appended decorators, which is where the name, percentage, ETA and byte counters live. The container, not the individual bar, decides when the terminal is redrawn, which is why the README lists decorator width synchronization as a feature: decor.Percentage(decor.WCSyncSpace) asks the container to pad that column to the widest value across bars so the columns line up. The repository layout shows how the pieces are separated: bar_heap.go and heap_manager.go hold the ordering of bars, console_writer.go writes to the terminal, and copy_buffer.go handles the intermediate buffer. The proxy types are the other half of the design. proxyreader.go, proxyreadseeker.go and proxywriter.go wrap an io.Reader, io.ReadSeeker or io.Writer so that a bar advances as bytes move through, without the calling code counting manually. That is the intended data flow: wrap the stream, hand the wrapper to your copy loop, and let the bar follow the bytes. The README also lists dynamic total (set the total while the bar is running), dynamic add and remove of bars, and cancellation of the whole rendering process.

## Installing mpb and rendering a first bar

The import path carries the major version, so the module line is github.com/vbauerster/mpb/v8, matching the module declaration in go.mod. Add it with go get, then write a program that creates a container and one bar. The README's single-bar example initializes the container with a custom width and creates a bar that inherits it, using mpb.BarStyle() with Lbound, Filler, Tip, Padding and Rbound to set the visual style. The code below follows that shape.

```go
package main

import (
	"time"

	"github.com/vbauerster/mpb/v8"
	"github.com/vbauerster/mpb/v8/decor"
)

func main() {
	p := mpb.New(mpb.WithWidth(64))
	bar := p.New(100, mpb.BarStyle().Lbound("╢").Filler("▌").Tip("▌").Padding("░").Rbound("╟"),
		mpb.PrependDecorators(decor.Name("Single Bar:")))
	for range 100 {
		bar.Increment()
		time.Sleep(10 * time.Millisecond)
	}
	p.Wait()
}
```

Run it with go run. You should see one bar advance from empty to full in the terminal, then the program exits when p.Wait() returns. The second README example is the multi-bar case and is the one worth copying if you have concurrent work: it creates a sync.WaitGroup, passes it to mpb.New via mpb.WithWaitGroup(&wg), calls wg.Add(numBars), and names each bar with fmt.Sprintf("Bar#%d:", i) inside decor.Name. The README notes that the passed WaitGroup is accounted for at the p.Wait() call, so p.Wait() blocks until the group drains. For a download loop, the proxy types replace manual Increment calls: wrap the response body in a proxy reader tied to a bar, and the bar follows the bytes as io.Copy reads them. The README points to _examples/io for that pattern, along with _examples/dynTotal and _examples/queueBar for the dynamic-total and queued-bar cases.

## Where mpb is the wrong choice

The container draws to the terminal, and that is the constraint that bites. If your program also writes ordinary log lines while bars are animating, the two outputs compete for the same rows; the repository includes stripansi and a console writer for handling escape sequences, but the README does not document a supported way to interleave free-form logging with an active render. Redirect the output to a file or a CI log and the escape sequences stop being useful. A second limitation is scale. The bars are held in a heap (bar_heap.go, heap_manager.go) and redrawn as a group, so a program that wants hundreds of simultaneous bars pays for the ordering and the redraw on every frame; the README gives no guidance on a sensible ceiling. Third, the ETA decorator is ewma-based, which means the estimate is smoothed from observed progress. That is a reasonable choice for steady transfers and a poor one for work with a long stall followed by a burst. Finally, the README does not document rollback or persistence: if the process dies mid-render, nothing in the library restores the terminal state, and there is no resume mechanism for the work being tracked. The bar is a display, not a job manager.

## How it differs from uiprogress and other Go bar libraries

The related searches around this project include Gosuri uiprogress, which is the closest comparison in the Go ecosystem. The difference is in who owns the render loop. uiprogress is built as a set of bars attached to an io.Writer, and the caller drives the refresh, typically from a ticker in the main goroutine; the bars are a data structure you print. mpb inverts that: you create a container, add bars to it from any goroutine, and the container owns the redraw and the ordering. That inversion is what makes dynamic add and remove and synchronized decorator widths possible without the caller coordinating them, and it is also what makes mpb harder to combine with other terminal output. The proxy reader types are a second difference. With mpb you can hand an io.Reader to io.Copy and let the bar track bytes automatically; the README treats this as a first-class usage pattern rather than an add-on. If your program already has a render loop you are happy with, or you only need one bar, the smaller writer-based libraries fit more naturally. If you have a pool of workers each producing its own bar and you do not want to write the redraw logic, mpb is the one doing that work for you.

## Maintenance, licence and the cost of upgrading

The repository is not archived and the last push was on 2026-08-24, the same date as the v8.16.0 release; v8.15.2 and v8.15.1 landed earlier in August 2026. That is a recent release cadence, but the version number is the thing to plan around. The module path is versioned as /v8, which means a v9 would arrive as a separate import path and a separate go.mod requirement rather than an in-place upgrade. Within v8, the API surface visible in the repository is broad (bar_option.go, container_option.go, bar_filler.go and its variants), so a minor bump can still touch option types you use. The licence is the Unlicense, which is a public domain dedication rather than a permissive licence with attribution terms; the repository carries an UNLICENSE file at the top level. That removes attribution obligations, but it also means there is no licence steward to ask about patent or warranty questions. This is a description of the file, not legal advice. The dependency floor is the go directive in go.mod, which declares Go 1.25.0, so a project pinned to an older toolchain cannot build it without moving that floor.

## Conclusion

Adopt mpb when a Go CLI needs several concurrent bars in one terminal block and the default decorators (elapsed time, ewma-based ETA, percentage, bytes) cover your output. Do not adopt it for a single one-line bar, for logging that must stay readable while bars animate, or for non-terminal output such as a CI log file. Before committing, run one of the _examples programs against your real writer and confirm how the draw loop behaves when you write a log line mid-render, and confirm your module can move to the Go version declared in go.mod.

## FAQ

### What is a progress bar used for?

In mpb's case it reports how far a long-running operation has advanced in a terminal program. The library renders multiple bars at once and can show elapsed time, an ewma-based ETA, a percentage and a byte counter alongside each one.

### How do I install vbauerster/mpb in a Go project?

Add the versioned module github.com/vbauerster/mpb/v8 with go get, then import github.com/vbauerster/mpb/v8 and github.com/vbauerster/mpb/v8/decor. The README's examples create a container with mpb.New and add bars with p.New or p.AddBar.

### Can vbauerster/mpb track a download without counting bytes manually?

Yes. The repository includes proxyreader.go, proxyreadseeker.go and proxywriter.go, which wrap an io.Reader, io.ReadSeeker or io.Writer so a bar advances as data passes through. The README points to _examples/io for this pattern.

### Does vbauerster/mpb support adding or removing bars while rendering?

The README lists dynamic add and remove of bars as a feature, along with setting the total while a bar is running and cancelling the whole rendering process. The _examples/dynTotal and _examples/queueBar programs cover those cases.

## Sources

- [Official README](https://github.com/vbauerster/mpb#readme)
- [Project repository](https://github.com/vbauerster/mpb)
- [Release notes](https://github.com/vbauerster/mpb/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vbauerster-mpb
