CLI tool
briandowns/spinner avatar
briandowns/spinner

spinner: ninety terminal progress indicators in one small Go package

Go (golang) package with 90 configurable terminal spinner/progress indicators.

2,530 stars131 forksGoApache-2.0

At a glance

What is it?
Two dependencies, one file of character sets and a spinner API small enough to read in a minute. The interesting parts are the release cadence and the build tooling the repo never retired.
Who is it for?
spinner is one of those packages you add in ninety seconds and never think about again, which is the highest compliment a utility library can earn. The API surface is a struct you construct, a Start method, a Stop method and a suffix or message field, and the ninety character sets are selected by integer index so they can be driven from configuration.
Can I use it commercially?
Yes. Apache-2.0 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 received new commits within the last day.
What is it written in?
Mainly Go, according to GitHub's language statistics.

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

Editorial analysis

What the package actually does

The whole purpose fits in the opening line: add a spinner or progress indicator to any terminal application. There is no configuration file, no daemon and no IPC. You import the package, construct a spinner, start it, do work, and stop it.

bash
go get github.com/briandowns/spinner

That is the entire installation. The dependency list in the module file is two entries, which is unusually lean for anything that touches a terminal:

code
require (
	github.com/fatih/color v1.7.0
	golang.org/x/term v0.1.0
)

The reason for both is visible from the name. `x/term` supplies terminal width and capability detection, which is what lets the spinner reposition its line correctly. `fatih/color` supplies colour output, which is what makes a spinner look like a spinner rather than a bare line of characters. Between them they account for every non-standard-library import, which is why the rest of this article can focus on maintenance questions rather than on architecture.

The documentation model is godoc-first, and the README says so directly: for more detail about the library and its features, reference your local godoc once installed. There is a `character_sets.go` file that is almost certainly a single large slice of strings, and a `spinner.go` that holds the type and its methods. Reading two files tells you everything, which is a legitimate design choice for a package this small.

Ninety character sets, addressed by index

The distinctive feature is the set collection. The README's table is numbered by slice index, and the numbers are the API. Index 0 is a set of arrows, index 1 is the ascending and descending bar `▁▃▄▅▆▇█▇▆▅▄▃▁`, index 2 is the four-corner set, index 3 is a box-drawing sweep, and so on through 89.

The library advertises ninety of them, and the table gives a sample gif for each. That detail matters more than it looks. A spinner is pure presentation, so the only honest way to review the collection is to watch it move. Sample gifs for all ninety sets live in a `gifs/` directory in the tree, which is a bigger commitment than most libraries make to aesthetics.

Because sets are addressed by integer rather than by name, the library can accept a character set from a command line flag, a config file or an environment variable without any string parsing on the library side. That is convenient, and it is also a sharp edge: an out-of-range index is a runtime failure in your program, and the error will surface at the moment the spinner starts rather than at the moment the user typed the flag. Validate the number yourself, or expose the sets by a curated subset of indices.

The sets are not all animations in the same sense. Some sweep an arc, some grow and shrink a bar, some rotate a two-frame glyph, and some walk the alphabet or count. If your program needs a spinner that reads clearly on a monochrome terminal or over ssh, test the specific index you picked rather than assuming the collection is uniform.

The release history is three tags, two of them silent

There are three releases and they tell a story worth reading.

v1.23.0 shipped on 2023-03-06 with an empty release body. v1.23.1 followed on 2024-06-13 with the only informative notes in the repository's history: a fix for CVE-2022-29526, credited to a first-time contributor, plus a consolidation of the dependencies behind the `IsTerminal()` API. v1.23.2 shipped on 2025-01-20, also with an empty body.

The security fix is the interesting one, and it connects back to that dependency list. CVE-2022-29526 is a known issue in the `fatih/color` line's area, and this package consumes that library for its output. The release note says the fix landed in v1.23.1. The module file still lists `github.com/fatih/color v1.7.0`, so whether your build is covered depends on whether v1.7.0 is the version that carries the fix or whether the maintainer patched around it. That is a question for the changelog of the dependency rather than for this repository, and it is a reasonable thing to check before you adopt a package that writes escape sequences to a terminal.

The cadence itself is slow and quiet. Roughly fifteen months between the first two tags, seven months to the third, and then nothing since January 2025 even though the repository was pushed on 2026-10-02. Twenty open issues against 2,530 stars is a low ratio, which suggests either that the package is genuinely finished or that issues are handled elsewhere. The description on the repository page says the package has 90 configurable indicators, and the character set table agrees, so the feature count is not aspirational.

For an active push to the default branch with no tag behind it, the practical question is which commit you want. There is no release-notes trail for anything after v1.23.2.

Build tooling the repository never retired

The tree is small enough to read in full, and it contains three things that belong to different eras of Go packaging.

The first is a `vendor/` directory, committed alongside a module file that declares `go 1.17`. Vendoring is optional under modules, and it means the dependency source is duplicated into the repository. The Makefile has a `check` target that copies the vendored packages into `${GOPATH}/src/`, which is a GOPATH-era workflow. Modules did not make that target wrong, but nothing about it is needed any more, and its presence tells you the Makefile has not been revisited in a long time.

The same Makefile still has the `go.mod` target that runs `go mod init` followed by `go mod tidy`, guarded by a `.PHONY` declaration and an existence check on the `go.mod` file name. That target exists to bootstrap a module that is already checked in. It is harmless and it will never run in normal use.

The second thing is dual continuous integration. The tree contains a `.circleci/` directory and a `.travis.yml` file, and the README badge points at CircleCI. Travis CI's hosted offering for open source ended years ago, so the Travis file is dead configuration. Its continued presence is a good signal of how rarely this repository's root files are edited, and a bad sign if you are trying to judge how actively it is maintained.

The third is the `_example/` directory. The leading underscore is a Go convention that excludes a directory from the build, which is the correct way to hold runnable examples without them becoming part of the package. The README points readers at it, so it is maintained as documentation even though it never compiles as part of the library.

Where it fits

The case for this package is a command line program in Go that spends long enough on a step to need feedback. That covers network calls, database queries, decompression, file walks and anything else where the process is working but the screen is empty.

The case against is a program that needs a progress bar rather than an indeterminate indicator, a spinner with a live percentage, or output that must go to a log file. This package is named for the indeterminate case and the README describes it that way. A spinner tells the user that something is happening, not how much of it is left.

Two practical notes for adoption. First, suppress the spinner when output is not a terminal. The dependency on `x/term` exists precisely so the library can tell, and a spinner that writes escape sequences into a redirected log file or a CI transcript makes output harder to read rather than easier. Check for the terminal before starting. Second, remember that stderr is usually the right stream for a spinner, since stdout may be piped into another command.

Beyond that, the size of the dependency is the deciding factor. Two libraries, one of which is terminal detection, is a small enough surface to reason about and small enough to vendor or audit. For that class of problem that is a good trade.

Editorial conclusion

spinner is one of those packages you add in ninety seconds and never think about again, which is the highest compliment a utility library can earn. The API surface is a struct you construct, a Start method, a Stop method and a suffix or message field, and the ninety character sets are selected by integer index so they can be driven from configuration. Two details deserve a look before you depend on it. The module still declares Go 1.17 and pins x/term at v0.1.0, which is old for a repository pushed in October 2026, and the tree carries both a vendor directory and a Travis CI configuration alongside a modern go.mod. Neither blocks adoption. Both tell you the project is maintained in a conservative, hands-off way.

Frequently asked questions

How do I add a spinner to a Go command line program?

Install the package, construct a spinner with the character set index you want, call Start, do the work, then call Stop. Because character sets are addressed by an integer, the index can come from a flag or a config file without any parsing inside the library. Guard the Start call on a terminal check so the escape sequences do not end up in redirected output.

How do I choose among the ninety character sets?

The README numbers every set by its slice index and links a sample gif for each, which is the only reliable way to review a pure-presentation feature. Some sweep an arc, some grow a bar, some rotate two glyphs, some walk the alphabet. Pick an index, then check it on the terminals your users actually have, including over ssh and in a monochrome environment.

What are the dependencies of the spinner package?

Two direct ones: github.com/fatih/color for colour output and golang.org/x/term for terminal capability and width detection. Everything else in the module file is an indirect dependency of those two. That is a small enough dependency surface to audit quickly, which matters for a package that writes escape sequences into a user's terminal.

What is the latest release of briandowns/spinner?

v1.23.2, published 2025-01-20. The release before it, v1.23.1 from 2024-06-13, is the only one with meaningful notes: it carries a fix for CVE-2022-29526 and a consolidation of the dependencies behind the IsTerminal API. The repository has been pushed to since, most recently 2026-10-02, so there is development beyond the newest tag.

Is this package suitable for showing progress percentage?

No, it is for indeterminate work. A spinner indicates that something is happening and gives no information about how much is left. If you need a determinate bar, a percentage counter or an ETA, you want a different package. Reserve this one for steps whose duration you cannot estimate.

Official sources

  1. briandowns/spinner on GitHub
  2. Issues
  3. License: Apache-2.0
  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/briandowns-spinner.svg)](https://hysenlabs.com/projects/briandowns-spinner)