Free — no signup required

Output Formatting: Humans vs. Machines

2 min read

Who Is Reading Your Output?

A robust CLI tool has two distinct audiences with incompatible needs:

  1. Humans sitting at a terminal who want readable, scannable output.
  2. Other programs — shell scripts, CI/CD pipelines, jq, grep — that need structured, parseable data.

Trying to serve both audiences with the same output format serves neither well.

Designing for Humans:

  • Use aligned columns or ASCII tables to make data scannable.
  • Use colors to highlight status: green for success, red for failure, yellow for warnings. But only when writing to a terminal — never when output is piped to a file or another program. Check sys.stdout.isatty() before emitting color codes.
  • Send progress indicators, status messages, and verbose logs to stderr (Standard Error), not stdout. This keeps the data stream clean.

Designing for Machines:

  • Machines cannot reliably parse ASCII tables or colored text.
  • Provide a --json or --format=json flag that switches output to structured JSON on stdout.
  • JSON output should be consistent: same keys, same types, every time. A machine consumer breaks if your schema changes unexpectedly.

The Golden Rule of stdout: Keep your data stream clean. If your tool outputs a list of IP addresses, don't print "Here are your IPs:" before the list. Just print the IPs. This allows users to pipe your output directly into grep, xargs, jq, or any other tool without needing to strip your prose first.

The stdout / stderr Split:

stdout  →  data (the result of the operation)
stderr  →  everything else (progress, warnings, errors, logs)

This split is what makes Unix pipelines work. When you run mytool list-servers | grep active, the shell connects mytool's stdout to grep's stdin. If your tool prints error messages to stdout, they get passed to grep and corrupt the data stream. Printing errors to stderr means they appear on the terminal for the human to see, while the pipeline continues to work correctly.

Interview Tip

A common interview question is: "What's the difference between stdout and stderr, and why does it matter?" The answer goes beyond "one is for errors." The key insight is that the stdout/stderr split is what makes Unix pipelines composable. Stdout is the data channel; stderr is the diagnostic channel. A tool that conflates them breaks every pipeline it's used in.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free