Colorize CLI Output with ANSI Codes
Add ANSI colour to CLI output only when the stream is a terminal and NO_COLOR is unset, respecting user preference.
Task
Implement colour that degrades gracefully when output is piped or colour is disabled.
When to use this
A CLI emits colour codes into log files and CI output, cluttering them with escape sequences.
Prerequisites
- A CLI in any language
- Access to TTY detection
- Respect for NO_COLOR convention
Steps
1. Detect a TTY and honour NO_COLOR.
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
const red = (s) => (useColor ? '\x1b[31m' + s + '\x1b[0m' : s);Expected output: Colour is applied only on interactive terminals and suppressed when NO_COLOR is set.
2. Verify output is clean when piped.
tool fail | cat -v | grep -c '\^\[' || echo 'no escape codes'Expected output: Piped output contains no escape sequences, keeping logs and CI clean.
Troubleshooting
Problem
Colour in logs anyway
Solution
Check the actual output file descriptor, not a global flag.
Problem
Colour lost in CI that supports it
Solution
Allow an explicit FORCE_COLOR override for CI where colour is wanted.
Limitations
- ANSI support varies by terminal.
- Colour can hurt accessibility; keep semantic labels too.
- Not a substitute for structured output.
What this recipe does
Implement colour that degrades gracefully when output is piped or colour is disabled.
A CLI emits colour codes into log files and CI output, cluttering them with escape sequences.
Prerequisites
- A CLI in any language
- Access to TTY detection
- Respect for NO_COLOR convention
Procedure
- Detect a TTY and honour NO_COLOR.
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
const red = (s) => (useColor ? '\x1b[31m' + s + '\x1b[0m' : s);
Expected result: Colour is applied only on interactive terminals and suppressed when NO_COLOR is set.
- Verify output is clean when piped.
tool fail | cat -v | grep -c '\^\[' || echo 'no escape codes'
Expected result: Piped output contains no escape sequences, keeping logs and CI clean.
How to confirm it worked
Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows interactive runs show colour, piped runs contain no escape codes, and NO_COLOR disables colour.
Troubleshooting
Colour in logs anyway — Check the actual output file descriptor, not a global flag.
Colour lost in CI that supports it — Allow an explicit FORCE_COLOR override for CI where colour is wanted.
Limitations
- ANSI support varies by terminal.
- Colour can hurt accessibility; keep semantic labels too.
- Not a substitute for structured output.