Skip to main content
ansicode

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[\x1b[31m (red, similarly 30–37)
\\033[\033[31m
\\e[\e[31m
ESC [ESC [ 3 1 m
hex1b 5b 33 31 6d

Live preview

Rendered in your browser via the same tokeniser the decoder uses — no terminal needed.

30–37

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

30black
31red
32green
33yellow
34blue
35magenta
36cyan
37white
39default foreground

Examples

bash
for c in 30 31 32 33 34 35 36 37; do printf "\033[${c}m■\033[0m"; done; echo
python
for c in range(30, 38): print(f'\x1b[{c}m{c}\x1b[0m', end=' ')
go
for c := 30; c <= 37; c++ { fmt.Printf("\x1b[%dm%d\x1b[0m ", c, c) }
javascript
for (let c = 30; c <= 37; c++) process.stdout.write(`\x1b[${c}m${c}\x1b[0m `)
c
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[31m and \x1b[91m?
\x1b[31m selects basic red (foreground 30–37, the standard 8 ANSI colours). \x1b[91m selects 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[31m look 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 31 to 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_COLOR and disable colours when piped to a file?
Check two things at startup: isatty(stdout) (skip colour when output isn't a terminal) and process.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 the no-color pitfall.

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

Related sequences

In the family cookbook

SGR cookbook · 2. 16-color basic — `\x1b[31m` and friends