cli-spinners: the JSON frame data behind terminal spinners, and when to use it directly
Spinners for use in the terminal
At a glance
- What is it?
- cli-spinners is a data package, not a renderer. It ships 70+ spinner definitions as a JSON file plus a typed JavaScript entry point, and it expects another library to handle timing and redraws. Here is what that split means in practice.
- Who is it for?
- Adopt cli-spinners when you are building a Node.js CLI or a spinner renderer and want a maintained catalogue of frame sets instead of hand-drawing Braille or arc characters yourself; the JSON file is also usable outside JavaScript, which is why Swift, Python, Rust, Go and Bash ports exist.
- Can I use it commercially?
- Yes. MIT 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 last received commits 11 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
cli-spinners ships frames, not a running spinner
The package solves one narrow problem: deciding what characters a busy indicator should cycle through, and how fast. Everything else about a spinner (starting it, erasing the previous frame, stopping it, deciding whether the output is even a TTY) is left to the caller. The README states this directly: "The list of spinners is just a JSON file and can be used wherever." The JavaScript entry point is a thin wrapper over that file plus one helper.
The intended audience is therefore two groups. The first is authors of CLI frameworks and spinner renderers who need a curated set of frame sequences and do not want to invent them. The second is anyone porting terminal behaviour to another language: the README lists a Swift port (CLISpinner), a Python port (py-spinners), a Rust port (spinners), a Go port (go-spinners), a Bash port (bash-cli-spinners) and a Neovim port (spinner.nvim). Those ports exist because the underlying data is language-neutral, not because the JavaScript API is portable.
If you are writing an ordinary Node.js CLI and just want a spinner on screen, the README points you at ora rather than at this package. That is an unusual thing for a README to do, and it is the clearest signal of the project's scope.
The data model: interval in milliseconds, frames as an array
Each entry in the exported object has exactly two documented fields. The README's example for the dots spinner shows an interval of 80 and a frames array of ten Braille characters. The README defines interval as "the intended time per frame, in milliseconds" and frames as "an array of frames to show for the spinner".
The word "intended" is doing work there. The package does not schedule anything, so interval is a recommendation to whatever consumes it. A renderer that sleeps for interval milliseconds after each frame will drift, because it ignores the time spent drawing and any other work in the event loop. A renderer that computes the frame index from elapsed time will not. The data supports both, and the package takes no position.
Frames are plain strings, not fixed-width tokens. Several classic spinner sets use single-column Braille or box-drawing characters, but the catalogue also includes sets whose frames differ in visual weight or in character count, so a consumer that assumes every frame occupies one column can misalign. The README does not describe a width contract, and the repository's test script does reference string-length as a dev dependency, which suggests length is checked in tests rather than guaranteed by the API.
randomSpinner() is the only function in the API surface. It returns one spinner object in the same shape as the named entries.
Installing cli-spinners and reading a spinner definition
The package is published to npm under the name cli-spinners. The README gives the install command and nothing else, so there is no CLI binary, no config file and no service to run.
npm install cli-spinnersThe package is ESM-only: package.json sets "type": "module" and the exports map points types at ./index.d.ts and the default entry at ./index.js. A CommonJS require will not resolve the default export. The engines field requires node >=18.20.
The README's usage example imports the default export and logs one named spinner. Note that the printed object is data, not a rendered animation.
import cliSpinners from 'cli-spinners';
console.log(cliSpinners.dots);
/*
{
interval: 80,
frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
}
*/A first real use is to pick a spinner and hand its interval and frames to a renderer you already control. The repository ships example.js and example-all.js at the top level, and the asciicast script runs example-all.js under asciinema, so the repository itself demonstrates the catalogue by iterating it rather than by animating one entry. If you want to see every spinner at once, the README points to a live demo on jsfiddle and notes that the header GIF is outdated.
What cli-spinners deliberately does not do
There is no start, stop, succeed, fail or clear method. There is no TTY check, so nothing in the package prevents a caller from writing escape sequences into a pipe or a CI log. There is no cursor handling and no line-clearing logic. The README does not document rollback, cancellation or error propagation because there is no state to roll back.
That makes cli-spinners the wrong tool in three concrete cases. If you want a spinner working in ten seconds with no renderer code, it is the wrong tool, and ora is the one the README names. If you need progress semantics (percentages, task trees, nested steps), the data model has no place to put them. If you are not on Node.js, the npm package is not what you want at all; the README's Related list is the correct starting point, and each port has its own API and release cadence that this project does not control.
The package is also not a good place to look for accessibility or terminal-compatibility guidance. Frame sets include Unicode that some terminals render as replacement characters, and the README offers no per-spinner notes on which fonts or encodings are safe. That judgement is left entirely to the consumer.
cli-spinners versus ora, and versus writing your own frames
The practical alternative in the same ecosystem is ora, which the README lists first under Related. The difference is architectural, not cosmetic. ora owns the render loop: it starts, updates text, stops, and clears output. cli-spinners owns none of that and instead supplies the character data that a renderer like ora consumes. Choosing between them is really choosing whether you want to write renderer code.
The other alternative is to write your own frames inline. That is a few lines for a simple rotation, and it avoids a dependency. What you lose is the catalogue: 70+ sets with intervals that were chosen by someone else, plus the cross-language consistency that comes from other projects porting the same JSON. You also lose the shared vocabulary, since spinner names like dots are recognisable to anyone who has read this file.
There is a third option worth naming: the ports. If you are writing Rust, spinners is the Rust port and it is a separate project with its own maintenance. The README presents these as related projects, not as supported targets, and nothing in this repository guarantees that a port stays in sync with spinners.json.
Maintenance, release history and licence
The repository is not archived, and the last push was on 2026-09-18, which is recent relative to the release history. The most recent release listed is v3.4.0 on 2026-01-13, following v3.3.0 on 2025-09-25 and v3.2.1 on 2025-09-17. So releases are infrequent and the codebase between them is small: the published files list is index.js, index.d.ts and spinners.json, and the test script runs ava plus a TypeScript check on the declaration file.
Upgrade cost is close to zero for consumers, because the API is one default export and one named function. The realistic upgrade risk is not breaking changes in code but changes in data: a frame set could be added, renamed or adjusted, and if your code indexes spinners by name rather than reading the object, a rename is a silent failure. The README does not document a naming stability policy, so pinning a version is the conservative choice for anything that ships to users.
The licence is MIT, stated in package.json and present as a license file at the repository root. MIT permits use, modification and redistribution provided the copyright notice and permission notice are retained; the package also carries a funding field pointing at GitHub Sponsors, which is optional support rather than a licence term. This is a description of the licence text, not legal advice.
Editorial conclusion
Adopt cli-spinners when you are building a Node.js CLI or a spinner renderer and want a maintained catalogue of frame sets instead of hand-drawing Braille or arc characters yourself; the JSON file is also usable outside JavaScript, which is why Swift, Python, Rust, Go and Bash ports exist. Do not adopt it expecting a working spinner: there is no start, stop or clear method, no TTY detection and no render loop, so if you want a finished indicator you want ora, and if you are not on Node.js you want one of the ports. Verify first that your runtime satisfies the engines field (node >=18.20), that your spinner consumer reads interval in milliseconds rather than seconds, and that your chosen frame set renders in the font and encoding of your target terminal, since cliSpinners.dots uses Braille patterns that some terminals do not have glyphs for.
Frequently asked questions
What is a spinner in programming, and what does cli-spinners provide?
A spinner is a small animated indicator that shows a process is still running. cli-spinners provides the frame data for those indicators: each entry has an interval in milliseconds and an array of frames, and the package itself does not draw or animate anything.
Is cli-spinners the same as ora?
No. The README says you probably want to use these spinners through the ora package, which handles the terminal rendering. cli-spinners only supplies the frame sets and a randomSpinner() helper.
How do I install cli-spinners and use it in a Node.js CLI?
The README gives npm install cli-spinners, then imports the default export and reads fields such as cliSpinners.dots.interval and cliSpinners.dots.frames. The package is ESM-only and package.json requires node >=18.20.
Can I use cli-spinners outside JavaScript?
The README states the list of spinners is just a JSON file and can be used wherever, and it lists ports for Swift, Python, Rust, Go, Bash and Neovim. Those ports are separate projects with their own maintenance.
Does cli-spinners start and stop the spinner for me?
No. The documented API is the spinner objects plus randomSpinner(), with no start, stop or clear methods and no TTY detection, so the caller has to run the render loop.
Official sources
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.
[](https://hysenlabs.com/projects/sindresorhus-cli-spinners)
Community notes