SGR 30–37 — Foreground color (8 basic)
Set foreground to one of black/red/green/yellow/blue/magenta/cyan/white.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1b[31m (red, similarly 30–37)\033[31m\e[31mESC [ 3 1 m1b 5b 33 31 6dLive preview
Rendered in your browser via the same tokeniser the decoder uses — no terminal needed.
Description
The 8 basic foreground colors map one-to-one to SGR parameters 30 black, 31 red, 32 green, 33 yellow, 34 blue, 35 magenta, 36 cyan, 37 white. SGR 39 returns the foreground to the terminal default without touching the background — the surgical complement to a full \x1b[0m reset. ECMA-48 §8.3.117 specifies the parameter range; every terminal in the support matrix above honors the full 30–37 + 39 surface, including the Linux console (in 8-colour mode) and conhost.exe / ConPTY. The actual rendered RGB is theme-dependent — there is no canonical 'ANSI red'. xterm's default theme paints 31 as #cd0000; macOS Terminal.app's default is #c33720; Solarized's red is #dc322f; the user's xresources / profile config can remap any of the 16 slots arbitrarily. Apps that need a specific shade must use 256-color or truecolor, not basic 31.
The portability traps are environmental, not parser-side. On the Linux console / fbcon the basic 8 fg + 16 bg slots are the only colours that render — \x1b[38;5;Nm (256-color) and \x1b[38;2;R;G;Bm (truecolor) silently quantize to the nearest of those 16. Linux console also implements bold-as-bright (\x1b[1;31m paints in bright red, not weight-31-red), so on that terminal SGR 90–97 is fully redundant with 1;3N. Two cross-environment pitfalls bite often: (1) emitting raw \x1b[31m from a shell script without checking isatty(stdout) leaks ^[[31m bytes when the user pipes to less (without -R) or to a file — use tput setaf 1 for portable scripts so terminfo consults $TERM and returns empty on dumb / non-TTY; (2) emit \x1b[0m (or at least \x1b[39m) before every newline and before exit, or color bleeds into the user's prompt. Always honour the de-facto NO_COLOR=1 env var when output is going to a terminal you don't control.
Disable foreground with \x1b[39m — surgical, leaves background and other attributes intact. Don't reach for \x1b[0m just to close a coloured span: that clobbers any bold / italic / bg you also set. For accessibility, pair colour with a textual prefix (✓ ok / ✗ failed) so color-blind users get the same signal — colour should reinforce a message, never carry it alone. For truecolor RGB control without theme dependency, see sgr-fg-truecolor; for the 256-colour palette indices that survive most multiplexers, see sgr-fg-256; for the matching background side, see sgr-bg-basic.
Spec citation: ECMA-48 §8.3.117 (SGR parameters 30–37, 39)
Parameters
| 30 | black |
| 31 | red |
| 32 | green |
| 33 | yellow |
| 34 | blue |
| 35 | magenta |
| 36 | cyan |
| 37 | white |
| 39 | default foreground |
Examples
for c in 30 31 32 33 34 35 36 37; do printf "\033[${c}m■\033[0m"; done; echofor c in range(30, 38): print(f'\x1b[{c}m{c}\x1b[0m', end=' ')for c := 30; c <= 37; c++ { fmt.Printf("\x1b[%dm%d\x1b[0m ", c, c) }for (let c = 30; c <= 37; c++) process.stdout.write(`\x1b[${c}m${c}\x1b[0m `)for (int c = 30; c <= 37; c++) printf("\x1b[%dm%d\x1b[0m ", c, c);Used in
Real-world tools that emit this sequence — anchors the bytes to commands you've already used.
- ls --colorblue = directory, green = executable, cyan = symlink (LSCOLORS defaults)
- grep --color, ripgrepred on the matched substring
- git diffgreen = added line, red = removed line
- gcc, clangred = error, magenta = warning, cyan = note
- bash, zsh prompts (PS1)
Frequently asked
Short answers to the questions developers actually search for this sequence.
- What's the difference between
\x1b[31mand\x1b[91m? \x1b[31mselects basic red (foreground 30–37, the standard 8 ANSI colours).\x1b[91mselects bright red (foreground 90–97, the second 8 colours added by aixterm). Many terminals also render\x1b[1;31m(bold + red) as bright red — the legacy 'bold-is-bright' hack — but the 90–97 codes are the unambiguous spelling and don't depend on the bold attribute.- Why does the same
\x1b[31mlook orange on one terminal and dark red on another? - The basic 8 colours have no canonical RGB definition — every terminal ships its own palette. iTerm2's 'Solarized Dark', macOS Terminal's 'Basic', xterm's defaults, and Windows Terminal's 'Campbell' all map
31to noticeably different reds. If you need pixel-exact colour, switch to truecolor (\x1b[38;2;R;G;Bm) — the basic 16 are inherently theme-controlled. - How do I respect
$NO_COLORand disable colours when piped to a file? - Check two things at startup:
isatty(stdout)(skip colour when output isn't a terminal) andprocess.env.NO_COLOR(any non-empty value means 'no colour' per the [NO_COLOR informal standard](https://no-color.org/)). The pair handles both pipes (mytool | less) and explicit opt-out. See theno-colorpitfall.
Terminal support
- xterm
- yes
- Linux console (fbcon)
- yes
- macOS Terminal.app
- yes
- iTerm2
- yes
- Windows Terminal
- yes
- cmd.exe / ConPTY
- yes
- kitty
- yes
- alacritty
- yes
- WezTerm
- yes
- Ghostty
- yes
- GNOME Terminal
- yes
- Konsole
- yes
- tmux
- yes
- GNU screen
- yes
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes | yes |