Skip to main content
ansicode

SGR 38;5;n — 256-color foreground

Pick a foreground color from the 256-color xterm palette.

Byte forms

Every common string-literal form so you can paste-and-search either direction.

\\x1b[\x1b[38;5;Nm
\\033[\033[38;5;Nm
\\e[\e[38;5;Nm
ESC [ESC [ 3 8 ; 5 ; N m
hex1b 5b 33 38 3b 35 3b <N> 6d

Live preview

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

red orange yellow green cyan magenta

Description

SGR 38;5;N picks a foreground colour from the xterm 256-colour palette. N is 0–255: 0–7 map to the 8 basic colours, 8–15 to their bright variants, 16–231 form a 6×6×6 RGB cube indexed by 16 + 36*r + 6*g + b where r, g, b each take 0–5, and 232–255 form a 24-step grayscale ramp from near-black to near-white. The background equivalent is \x1b[48;5;Nm. Spec lineage: the parameter shape comes from xterm-ctlseqs (not ECMA-48 directly — ECMA-48 reserves 38 + 48 for 'future use' and lets implementations pick the sub-parameter grammar). Most parsers accept either the semicolon form \x1b[38;5;Nm (xterm legacy) or the ECMA-48-compliant colon form \x1b[38:5:Nm — emit semicolons by default; colons are safer only when you know the consumer (some libraries) handles them.

Portability is the whole story for 256-colour. The Linux console / fbcon ignores \x1b[38;5;Nm entirely (the palette is fixed at the 16 basic + bright entries) — every 256-indexed colour silently quantizes to the nearest of those 16. Apple's /usr/bin/screen (still v4.00.03 from 2006 as of macOS Sequoia) and Ubuntu 22.04 / Debian Bookworm's screen 4.09 also drop unknown 256-colour bytes; the multiplexer interprets the sequence before forwarding, and old screen versions never learned the form. Windows conhost.exe (legacy cmd host, not the modern Windows Terminal) quantizes to the 16 console-palette slots — ConPTY on 1809+ passes the bytes through unchanged, but the renderer above quantizes. Inside tmux, \x1b[38;5;Nm survives the multiplexer (it's only truecolor 38;2;… that needs the Tc/RGB terminfo cap). The portable feature-detect is $TERM containing 256color plus tput colors ≥ 256 — don't trust $COLORTERM for 256-colour (it's the truecolor flag).

Disable foreground with \x1b[39m — restores terminal default without touching the background or other attributes. The surgical close pair is \x1b[38;5;Nm…\x1b[39m; reaching for \x1b[0m clobbers any bold / italic / bg you also set. Don't forget to reset before newlines so colour doesn't bleed into the user's prompt (see color-bleed). For arbitrary RGB control beyond the 256-palette, see sgr-fg-truecolor (24-bit, no quantization on modern terminals); for the 16 basic + bright slots that render everywhere from Linux console to legacy conhost, see sgr-fg-basic; for the matching background side, see sgr-bg-256. The 256-colour cube is the right default when you need theme-independent colour but want maximum portability — it's the largest palette that survives most multiplexer + legacy-terminal hops without quantization, with truecolor as the modern-stack upgrade.

Spec citation: xterm-ctlseqs (256-color extension)

Examples

bash
for n in 16 51 196 226 51 21 201; do printf "\033[38;5;${n}m■\033[0m"; done; echo
python
for n in [16, 196, 226, 21, 51, 201]: print(f'\x1b[38;5;{n}m■\x1b[0m', end='')
go
for _, n := range []int{16,196,226,21,51,201} { fmt.Printf("\x1b[38;5;%dm■\x1b[0m", n) }
javascript
[16,196,226,21,51,201].forEach(n => process.stdout.write(`\x1b[38;5;${n}m■\x1b[0m`))
c
int n[] = {16,196,226,21,51,201}; for (int i=0;i<6;i++) printf("\x1b[38;5;%dm■\x1b[0m", n[i]);

Used in

Real-world tools that emit this sequence — anchors the bytes to commands you've already used.

  • batsyntax themes — Solarized, OneDark, Monokai use the 256-colour palette
  • eza (modern ls)
  • deltagit pager — language tokens use 256-colour syntax theme
  • tig (git TUI)
  • vim, neovim (default for 256-colour terminals)

Frequently asked

Short answers to the questions developers actually search for this sequence.

How do I map a hex colour to the nearest xterm-256 palette index?
For the 6×6×6 RGB cube, quantize each channel to 0–5 with round(c * 5 / 255), then compute the index as 16 + 36*r + 6*g + b. For near-greyscale targets, 232 + round(luma * 23 / 255) against the grayscale ramp often gives a better match than the cube. The cube doesn't cover every hex evenly — near-blacks and near-whites land more cleanly on the ramp. Production libraries (chalk, colorama, rich) ship optimised lookups that consider perceptual distance against the actual rendered palette.
Why does my 256-palette gradient render banded?
The 6×6×6 cube gives only 6 levels per channel, so a smooth blue-to-cyan run quantizes to a handful of distinct slots regardless of how many cells you generate — adjacent cells collapse onto the same index. The fix is one of: (1) emit truecolor (\x1b[38;2;R;G;Bm — 256 levels per channel) when $COLORTERM=truecolor is set, with a 256-cube fallback otherwise; or (2) pre-quantize your gradient steps to distinct cube indices so each cell jumps a slot instead of stuttering.

Terminal support

xterm
yes
Linux console (fbcon)
no
macOS Terminal.app
yes
iTerm2
yes
Windows Terminal
yes
cmd.exe / ConPTY
partial
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 · 3. 256-color indexed — `\x1b[38;5;n m`