How to Use Gum: The Beginner’s Guide to Glamorous Shell Scripts

CodexFuse Team · 2026-11-02T02:36:04.902Z · 14 min read min read

Gum is Charm’s CLI toolkit that makes shell scripts glamorous: this beginner’s guide covers installing it, choose, input, confirm, spin, style, and the stderr lesson, then builds a conventional-commit helper script.

How to Use Gum: The Beginner's Guide to Glamorous Shell Scripts

When you search for how to use gum, the first thing to know is that this guide is not about chewing gum — it is about Gum, the command-line toolkit from Charm that makes your shell scripts glamorous. This gum tutorial walks you through installing it, learning each command family, and building your first script. If you write bash scripts that lean on plain read prompts and hope the user types the right thing, Gum gives you pickers, confirm dialogs, spinners, and styled output with a single command each.

What Is Gum, Exactly?

Gum is a CLI toolkit from Charm that adds 13 small interactive commands to your shell scripts — so you can build pickers, inputs, confirmations, spinners, tables, and styled output without writing any Go code. It is the fastest way to turn plain automation into interactive shell scripts. Each command does one thing: gum choose shows a list, gum input reads a line of text, gum confirm asks yes or no, gum spin shows a spinner while another command runs, and so on. The full set is choose, confirm, file, filter, format, input, join, pager, spin, style, table, write, and log. It is the tool you reach for when a script needs a human decision but you do not want to build a full terminal UI. Developers who already live in the terminal — the kind who keep a persistent session open with our tmux beginner guide — find Gum a natural next step.

Installing Gum on Your System

Install Gum once, using your platform's normal package flow. The commands below come from the project's README, and the current release is v2.0.2 (the v2 line upgraded the internals to Bubble Tea and Lip Gloss v2 with no user-facing changes, so everything you read here works the same).

PlatformInstall command
macOS or Linux (Homebrew)brew install gum
Debian / UbuntuCharm apt repo: curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg, then add deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * * to /etc/apt/sources.list.d/charm.list, then sudo apt update && sudo apt install gum
Fedora / EPEL 10dnf install gum
Fedora / RHEL / openSUSE (Charm repo)sudo rpm --import https://repo.charm.sh/yum/gpg.key, add the charm.repo file from https://repo.charm.sh/yum/, then install with yum or zypper
Arch Linuxpacman -S gum
Nixnix-env -iA nixpkgs.gum
Floxflox install gum
Windowswinget install charmbracelet.gum or scoop install charm-gum
FreeBSDsudo pkg install gum (or via ports)
Go toolchain (any platform)go install charm.land/gum/v2@latest

Verify the install with gum -v or gum --version. If you use Homebrew for other command-line tools, our Homebrew beginner guide covers the same install pattern.

Your First Gum Command: gum choose

gum choose is Gum's list picker: it prints a list of options as an interactive menu, and the user's selection comes back as text on stdout. Run this to feel it:

printf '%s' "Pizza
Sushi
Tacos" | gum choose --header "Pick dinner"

You get a navigable list — arrow keys to move, Enter to pick — and the chosen word prints to stdout. That pattern, choice from the menu becomes the value in your script, is the whole idea behind Gum's pickers. Two flags matter immediately: --limit 5 lets the user pick up to five items, and --no-limit lets them pick as many as they like. Also useful: --header for a prompt line above the list, --select-if-one to skip the menu when only one item exists, and --cursor to change the cursor character.

Why NAME=$(gum input) Works: The Stderr Lesson

Gum renders its interactive UI to stderr and prints only the final answer to stdout — which is exactly why NAME=$(gum input) captures the typed value and nothing else. This split is the single most important thing to understand about Gum. The menu, the prompt, the spinner animation: all of it goes to stderr, where your terminal shows it but your pipes never see it. The data — the selected choice, the typed line, the confirmed answer — goes to stdout, so it flows into variables and pipes cleanly. Two exit-code facts round out the picture: pressing Ctrl+C during a Gum prompt exits with code 130, and a prompt that hits its --timeout writes "timed out" to stderr and exits 124.

Asking for Text: gum input and gum write

gum input reads one line of text with a prompt, placeholder, and optional default value; gum write opens a small multi-line editor for longer answers. A polished prompt looks like this:

NAME=$(gum input --prompt "* " --placeholder "Your name" --value "Ada")

The --placeholder shows ghost text before the user types, --value pre-fills an answer they can edit, and --prompt changes the leading character. For sensitive input, gum input --password masks the typing. Styling comes along for free: flags like --cursor.foreground "#FF0" and --width 80 tune the look. When one line is not enough — a commit message body, a note, a description — use gum write, which opens a multi-line text area with line numbers; the finished text prints to stdout when the user confirms.

Yes or No: gum confirm and the Exit-Code Lesson

gum confirm does not print "yes" or "no" — its answer is the exit code: 0 for affirmative, 1 for negative. So you never capture its output; you branch on it:

gum confirm "Delete the old backups?" && rm -rf backups/old

If the user picks yes, the command after && runs; if no, the exit code 1 stops it. Use $? if you need the value explicitly. The flags tune the dialog: --affirmative and --negative rename the two buttons ("Ship it" / "Hold"), --default pre-selects an option, and --timeout auto-answers after N seconds.

Long-Running Commands: gum spin

gum spin wraps any command with an animated spinner, keeping the screen alive while slow work happens. The basic shape is:

gum spin --spinner dot --title "Deploying..." -- ./deploy.sh

The title explains what is happening; the spinner animation shows progress is being made. Choose a spinner style with --spinner — options include line, dot, minidot, jump, pulse, points, globe, moon, monkey, meter, and hamburger. Add --show-output when you want the wrapped command's output visible or piped while it runs. A spinner plus a clear title is the difference between a script that feels frozen and one that feels alive.

Picking Files: gum file and gum filter

gum file is an interactive file picker that walks a directory tree; gum filter is a fuzzy finder over whatever you pipe in. Open an editor on a chosen file with one line:

$EDITOR $(gum file $HOME)

By default Gum picks files; pass --directory to pick directories instead. Useful flags: -a/--all shows hidden dotfiles, --height controls the menu size, and --timeout aborts with no selection after N seconds. For anything that is not the filesystem, pipe text into gum filter and get a searchable list — git branch | gum filter to pick a branch, for example.

Turning Data into Choices: gum table and gum log

gum table turns CSV-style data into a selectable table; gum log prints structured, leveled log lines from your scripts. Feed a CSV through gum table and pick a row:

gum table < flavors.csv

Rows split on the --separator flag (comma by default); --columns lets you name and constrain columns. For script output, gum log gives you levels and structure:

gum log --structured --level debug "Creating file..." name file.txt

This prints a debug-level line with a name=file.txt field. Flags include --level (none, debug, info, warn, error, fatal), --formatter (json, logfmt, or text), --time for timestamp formats, and --file to log to a file instead of the terminal. A script that logs with levels is dramatically easier to debug than one that echoes bare text.

Laying Out Output: gum join, gum style, and gum format

Gum's layout commands — join, style, and format — compose and beautify your script's output without printf gymnastics. gum join places text blocks side by side (horizontally by default; --vertical stacks them, --align centers or edges them). gum style adds borders and color to a single block:

gum style --foreground 212 --border-foreground 212 --border double --align center --width 50 --margin "1 2" --padding "2 4" 'Deploy finished' 'Everything is green.'

Colors accept ANSI codes, hex values, and names; --border takes styles like double and normal. gum format renders markdown, code, templates, and emoji passed on stdin:

gum format <<'EOF'
# Gum Formats
- Markdown
- Code
- Template
- Emoji
EOF

Use --type (or -t) to pick between markdown (the default), code, template, and emoji. Printing a readable summary at the end of a script is the cheapest way to make it feel professional, and gum format does it in one line.

Your First Script: A Conventional-Commit Helper

The fastest way to learn Gum is to build one script that chains choose, input, write, and confirm into a conventional-commit helper. This five-step arc uses four Gum commands the way real scripts do:

  1. Choose the commit type. Feed the type list into gum choose and capture the result:
    TYPE=$(gum choose --header "Commit type" <<'EOF'
    feat
    fix
    docs
    refactor
    test
    EOF
    )
  2. Input the scope. SCOPE=$(gum input --placeholder "scope" --prompt "* ") reads one word like auth.
  3. Write the body. BODY=$(gum write --placeholder "What changed and why...") collects the longer explanation.
  4. Confirm before committing. Show the assembled message with gum style or gum format, then gate the commit: gum confirm "Commit as $TYPE$SCOPE?" || exit
  5. Commit. git commit -m "$TYPE($SCOPE): $SUMMARY" -m "$BODY" runs only after the user said yes.

Every input is validated by construction — the type can only be one of the list items, the scope and body come from guided prompts, and nothing commits without an explicit yes. If you are new to Git itself, our Git beginner guide covers the commit model this script assumes.

Skimming Long Output: gum pager

gum pager scrolls long text through a built-in viewport with line numbers — it is not a wrapper around less. Run gum pager < README.md and you get a navigable, styled viewer implemented in Bubble Tea, with no external pager dependency to install. Reach for it at the end of a script when the output is longer than a screen: print the summary with gum style, and offer the full log through gum pager.

The 13 Gum Commands at a Glance

Gum ships 13 user commands: choose, confirm, file, filter, format, input, join, pager, spin, style, table, write, and log. This table maps each one to its job and a signature example so you can see the whole toolkit on one page.

CommandWhat it doesSignature example
gum chooseInteractive list picker; selection to stdoutgum choose "Pizza" "Sushi" "Tacos"
gum confirmYes/no dialog; answer is the exit code (0/1)gum confirm "Ship it?" && deploy
gum fileInteractive file picker walking a directory tree$EDITOR $(gum file $HOME)
gum filterFuzzy finder over piped inputgit branch | gum filter
gum formatRenders markdown, code, templates, emojicat NOTES.md | gum format
gum inputSingle-line text prompt with placeholder and defaultNAME=$(gum input --placeholder "name")
gum joinJoins styled blocks horizontally (or vertically)gum join --vertical "$A" "$B"
gum pagerBuilt-in viewport pager with line numbers, not lessgum pager < long.log
gum spinAnimated spinner around a long-running commandgum spin --title "Working..." -- make
gum styleBorders, colors, padding, and margins for textgum style --border double "Done"
gum tableSelectable table from CSV-style datagum table < flavors.csv
gum writeMulti-line text editor area for longer answersBODY=$(gum write --placeholder "notes")
gum logLeveled, structured log lines for scriptsgum log --level info "saved"

Gum vs Whiptail and Dialog

If you know whiptail or dialog — the classic terminal dialog-box utilities of the 1990s — Gum is the modern successor: same idea (dialogs from shell scripts), but with per-command binaries, fuzzy filtering, styled output, and a component model built on Charm's Bubble Tea. Whiptail and dialog draw box-drawn widgets and return results through file descriptors and exit codes; Gum does the same job with prettier rendering and a much smaller per-widget API — one command per widget instead of one giant flag soup. Two other Charm tools share the ecosystem but never compete with Gum: glow, Charm's terminal-based markdown reader, and vhs, their CLI home-video recorder that turns terminal sessions into GIFs for docs and demos (the Gum README's own demo GIFs are vhs recordings).

7 Beginner Mistakes to Avoid

MistakeWhat happensThe fix
Capturing gum confirm outputconfirm prints nothing — your variable is empty and the real answer (the exit code) is lostBranch on it: gum confirm "Go?" && go or check $?
Forgetting the stderr/stdout splitPiping a script and wondering why the menu text shows in the terminal but never in the pipeRemember: the UI renders to stderr, the data prints to stdout — pipes only ever see the data
Using --print on gum tableThat flag does not exist on the current gum table commandUse --separator and --columns; check gum table --help for the real flags
Teaching Ctrl+C as successCtrl+C exits with code 130, not a clean 0 — scripts that ignore it can leave half-finished stateHandle 130 explicitly, or let set -e stop the script
Picking directories with plain gum fileFiles are selected by default; directories are notPass --directory when you want folder picking
Installing v1 docs commandsOld guides still show charmbracelet/gum Go paths and pre-v2 layoutsUse go install charm.land/gum/v2@latest; the v2 module path is the current one
Building every widget as raw ANSIHand-rolled escapes are brittle across terminals and break on resizeOne gum style or gum format call replaces the escape-code mess

Sources

  1. charmbracelet/gum releases page — v2.0.2 current release ("No more raw ANSI sequences"), v2.0.1, v2.0.0 ("no UX changes", Bubble Tea/Lip Gloss v2, module renamed to charm.land/gum/v2), v0.17.0 ("Pad Everything" --padding) — https://github.com/charmbracelet/gum/releases
  2. gum README, main branch — full 13-command list, verbatim install matrix, gum choose examples (--limit/--no-limit), gum input flags (--placeholder, --prompt, --value, --password), gum confirm exit-code semantics, gum spin (--show-output, spinner types), gum file, gum table, gum log --structured, gum join, gum style, gum format stdin example, gum pager — https://raw.githubusercontent.com/charmbracelet/gum/main/README.md
  3. gum.go, main branch — utility commands completion and man, -v/--version flag, pager described as a shell interface for the viewport bubble — https://raw.githubusercontent.com/charmbracelet/gum/main/gum.go
  4. DeepWiki charmbracelet/gum "Getting Started" — stderr rendering for interactive commands, stdout for data output — https://deepwiki.com/charmbracelet/gum/2-getting-started
  5. DeepWiki charmbracelet/gum "Formatting Commands" — Ctrl+C exits 130, --timeout writes "timed out" to stderr and exits 124 — https://deepwiki.com/charmbracelet/gum/4-formatting-commands
  6. pkg.go.dev gum/format package — stdin markdown input, -t/--type markdown/code/template/emoji — https://pkg.go.dev/github.com/charmbracelet/gum/format
  7. pkg.go.dev gum/table package — -s/--separator (default ","), -c/--columns — https://pkg.go.dev/github.com/charmbracelet/gum/table
  8. pkg.go.dev gum/log package — -s/--structured, -f/--format, --formatter (json/logfmt/text), -l/--level, -t/--time, -o/--file — https://pkg.go.dev/github.com/charmbracelet/gum/log
  9. pkg.go.dev gum/choose package — --ordered, --header, --select-if-one — https://pkg.go.dev/github.com/charmbracelet/gum/choose
  10. tech.aufomm.com personal guide (~July 2026) — newest independent usage walkthrough found; gum confirm --help flags (--affirmative/--negative/--default/--timeout) — https://tech.aufomm.com/how-do-i-use-charmbracelet-gum-to-improve-my-scripts/
  11. hexmos.com freedevtools gum tldr — command examples; whiptail/dialog cross-referenced under "See also" — https://hexmos.com/freedevtools/tldr/common/gum/
  12. x-cmd.com gum install page — product/setup page, install commands plus feature summary — https://www.x-cmd.com/install/gum/
  13. Maciej Walkowiak, "Beautiful bash scripts with gum" (Nov 2022) — 4-year-old personal guide predating table/log/pager/format — https://maciejwalkowiak.com/blog/beautiful-bash-scripts-with-gum/
  14. Trendoceans, "Gum tool Linux" (~2022) — 4-year-old personal guide predating table/log/pager/format — https://trendoceans.com/gum-tool-linux/

Frequently Asked Questions

Is this guide about chewing gum?

No. This guide is about Gum, the command-line toolkit from Charm (charmbracelet/gum) that adds interactive pickers, inputs, spinners, and styled output to shell scripts. Search results for "how to use gum" are heavily polluted by chewing-gum and dental content; adding "charm" or "cli" to your query disambiguates.

What is gum charm used for?

Making shell scripts interactive and readable. Instead of bare read prompts, you get a list picker (gum choose), text prompts (gum input, gum write), yes/no dialogs (gum confirm), spinners (gum spin), file pickers (gum file), CSV tables (gum table), styled output (gum style), and structured logs (gum log) — 13 small commands you call from any shell, with no Go code.

How do I install gum on Linux?

On Debian/Ubuntu, add Charm's apt repo (the GPG key and sources.list steps are on the project's README) and run sudo apt install gum. On Fedora/EPEL, dnf install gum; on Arch, pacman -S gum. On any Linux with Homebrew, brew install gum. Go users can run go install charm.land/gum/v2@latest.

Why does gum confirm not print anything?

Because its answer is the exit code, not text: 0 for affirmative, 1 for negative. Branch on it directly with gum confirm "Delete?" && rm file or inspect $?. Capturing its output into a variable is the most common beginner mistake.

How is gum different from whiptail or dialog?

Same job — dialogs from shell scripts — but modern: one command per widget instead of one giant flag soup, fuzzy filtering (gum filter), CSV table picking (gum table), markdown rendering (gum format), and styled output built on Charm's Bubble Tea and Lip Gloss. The classic tools still work; Gum is the prettier, more composable successor.

Featured on Twelve Tools Launch Llama Tools Launch your MCP