The TUI
Most CLI apps run for a moment, write some output, and then exit. Think ls. But there's a category of full-blown apps that hang around so you can interact with them. This kind of app is called a Terminal User Interface, or TUI for short. A broad definition would technically include stalwarts like emacs or tmux, but here we are mainly focused on newer TUIs that strive for beautiful design with advanced layouts.
Disclaimer - I've only written a handful of TUI apps, mostly unreleased. My favorite is probably my silly little RPN calculator vectro, built with bubbletea. Also on web at vectro.app, which nobody asked for. It's not that exciting, please ignore.
Gratuitous Screenshots
Let your imagination run wild, we can do a lot these days:
Ecosystem
If you think about it, each TUI must include the crude equivalent of a web browser - event loop, layout engine, and widgets. TUI libs are powerful and complicated. Some of them are like react, with nested components and props. Some use flexbox. Let's start by checking out some popular TUI apps. I award a highly-coveted chicken emoji to apps I've used and enjoyed. 🐔
| app | lang | ⭐ stars | tui lib | what |
|---|---|---|---|---|
| fx 🐔 | go | 21k | bubbletea | json viewer |
| gh-dash | go | 12k | bubbletea | gh dashboard |
| slides | go | 12k | bubbletea | slides |
| superfile | go | 23k | bubbletea | file manager |
| memray | py | 15k | textual | py memory prof |
| posting | py | 12k | textual | like postman |
| bandwhich 🐔 | rs | 12k | ratatui | bandwidth monitor |
| csvlens | rs | 4k | ratatui | csv viewer |
| elio 🐔 | rs | 1k | ratatui | file manager |
| gitui | rs | 22k | ratatui | git |
| llmfit 🐔 | rs | 31k | ratatui | local LLM picker |
| presenterm | rs | 9k | ratatui | slides |
| spotify-player | rs | 7k | ratatui | spotify |
| trippy 🐔 | rs | 7k | ratatui | ping |
| yazi 🐔 | rs | 41k | ratatui | file manager |
| gloomberb | ts | 1k | opentui | finance |
| hunk 🐔 | ts | 8k | opentui | diff viewer |
| btop | c++ | 33k | custom | top |
| glances | py | 33k | ncurses | top |
| goaccess | c | 21k | ncurses | log file viewer |
| k9s | go | 34k | tview | kubernetes |
| lazydocker | go | 52k | gocui | docker |
| lazygit 🐔 | go | 81k | tcell | git |
| nnn | c | 22k | ncurses | file manager |
| spotify-tui | rs | 19k | tui-rs | spotify |
| tig 🐔 | c | 13k | ncurses | git |
And let's not forget the ai harnesses:
| app | lang | ⭐ stars | tui lib |
|---|---|---|---|
| claude-code 🐔 | ts | 140k | ink |
| codex 🐔 | rs | 91k | ratatui |
| copilot-cli | ts | 11k | ink |
| gemini-cli | ts | 106k | ink |
| hermes-agent | py/ts | 222k | ink |
| opencode | ts | 191k | opentui |
| pi 🐔 | ts | 90k | custom |
TUI Frameworks
Again, I haven't used all of these so I can't really provide a lot of guidance. The only one I've shipped with is bubbletea, which I found to be fast and productive. Personally I would avoid writing complicated TUIs in typescript. Use something native like go/rust, and probably bubbletea/ratatui if you have a choice.
| lib | lang / cloc | ⭐ stars | design | layout |
|---|---|---|---|---|
| bubbletea 🐔 | go / 24k | 44k | model/update/view | lipgloss / manual |
| ink | ts / 54k | 40k | react | flexbox |
| opentui | ts / 93k | 13k | react/solid | flexbox |
| ratatui 🐔 | rust / 21k | 22k | immediate mode | constraints |
| textual | python / 46k | 37k | react-like | css-like |
Bubbletea cloc includes deps like Ultraviolet, Ink includes React, Textual is ts+zig. These frameworks are beasts.
Rendering
TUI frameworks have an interesting set of constraints. In general, the bottleneck is not widgets or layout - it's pushing display commands (ansi escape codes) to the terminal. When I was working on my ansi movie player, I could run at thousands of fps as long as I was targeting /dev/null. Inside a real terminal, that abruptly dropped to 25 fps. So how do these TUIs work?
-
bubbletea / opentui / ratatui - On each render, these frameworks rebuild the complete frame and diff against the previous frame. They emit only the ansi commands needed to bring the terminal up to date, with optimizations to keep that output small. The bottleneck is the terminal.
-
ink - My understanding is that this thing wasn't built for speed, and does full frame re-renders by default. The major harnesses use custom rendering to calculate diffs like the other frameworks.
-
textual - Textual tracks dirty rectangles, much like a traditional windowing system. Probably overkill for terminals, an approach that's largely been rejected by other TUI frameworks.








