Skip to content

1.1 What Is a TUI?

A TUI (Terminal User Interface) is an interactive program that runs inside a terminal emulator and uses text, colors, and cursor positioning to build a visual interface — without a graphical window system.

┌─────────────────────────────────────────────┐
│ lazygit q:quit │
├──────────────┬──────────────────────────────┤
│ Branches │ Commits │
│ > main │ • feat: add login page │
│ dev │ • fix: broken redirect │
│ feature/x │ • chore: bump deps │
├──────────────┴──────────────────────────────┤
│ Diff │
│ + const user = await getUser(id); │
│ - const user = db.find(id); │
└─────────────────────────────────────────────┘

That is a TUI. Everything you see — the boxes, colors, the cursor highlight — is made of characters and ANSI escape codes sent to a terminal.

1970s — curses: Unix programs needed a way to position text anywhere on screen, not just print line by line. The curses library (later ncurses) gave C programs a grid-based drawing API. Most classic terminal tools — vi, pine, mutt — were built on it.

1980s–90s — DOS TUIs: MS-DOS had no windowing system, so rich UIs were built entirely in text: Norton Commander, WordPerfect, Borland IDEs. These pioneered box-drawing characters and color attributes.

2000s — GUI dominance: As graphical desktops matured, TUIs were seen as legacy. New developer tools defaulted to GUI.

2010s–2020s — The Renaissance: DevOps culture brought developers back to the terminal. Tools like htop, tmux, vim/neovim, and later Go-based tools (lazygit, k9s) proved that TUIs can be faster, scriptable, composable, and beautiful.

2026 — Where we are: TUI is a first-class choice. Libraries exist in Go (Bubble Tea), Rust (Ratatui), and TypeScript. Terminal emulators now support true 24-bit color, images (Sixel/Kitty protocol), and Unicode box-drawing at full resolution.

Every TUI program, no matter the language or library, has the same three responsibilities:

┌─────────────┐ keypresses, resize ┌─────────────┐
│ Terminal │ ─────────────────────────► │ │
│ Emulator │ │ Your App │
│ │ ◄───────────────────────── │ │
└─────────────┘ ANSI escape sequences └─────────────┘
  1. Receive input — keyboard events, mouse events, terminal resize signals
  2. Update state — process the input, change the application’s data model
  3. Render output — translate state into ANSI escape sequences and write them to stdout

This is the same loop as a game engine. In fact, a TUI and a terminal game are the same thing with different content.

A CLI (Command Line Interface) runs, prints output, and exits. You cannot interact with it while it’s running.

A TUI is persistent and interactive:

CLITUI
Runs once, exitsRuns until user quits
Scrolling outputFull-screen drawing
No cursor controlFull cursor positioning
git statuslazygit
kubectl get podsk9s

Go and Rust dominate the current TUI landscape because they compile to fast static binaries. But TypeScript has real advantages for learning and prototyping:

  • No compile step with tsx — save and run instantly
  • Familiar for web developers — same language, different environment
  • Node.js built-ins are excellent: process.stdin, readline, process.stdout
  • For the sizes of TUIs most developers build, Node.js speed is more than sufficient

In this course we start with raw Node.js + minimal libraries so you understand exactly what is happening. Later lessons show you how to build abstractions.

By the end of this course you will have:

  1. A reusable TypeScript TUI component library (boxes, menus, inputs, layouts)
  2. A Task Manager TUI — a real app that reads and edits tasks interactively
  3. A Snake game — fully playable, with score, speed increase, and game-over screen

All from scratch. Let’s start.