pino-pretty
A CLI and stream that prettifies Pino's ndjson log lines into readable, colorized terminal output for local development.
Repository Health
Technical Analysis
pino-pretty is the companion formatter for the Pino logging library. Pino itself is deliberately minimal in production, emitting raw ndjson log lines for speed, but that format is hard to read at a glance during development. pino-pretty takes those lines (or any ndjson-looking input) and renders them as colorized, human-readable text, showing the timestamp, level, message, and any attached metadata or error stack traces in a compact single- or multi-line layout.
It can be used two ways: as a standalone CLI that you pipe Node’s stdout through (node app.js | pino-pretty), or as a programmatic stream that plugs directly into Pino’s transport system (pino({ transport: { target: 'pino-pretty' } })). Both paths share the same underlying formatter, so CLI flags and programmatic options mirror each other one-to-one (e.g. --colorize / colorize, --translateTime / translateTime).
Beyond basic prettifying, it supports custom level names/colors, a small message-templating language (messageFormat, including {if x}...{end} conditionals), per-key custom prettifier functions, key filtering via ignore/include, and config files (.pino-prettyrc) discovered automatically via joycon. It is explicitly recommended only for development use — Pino’s own docs steer production deployments away from it for performance reasons.
What You Get
- A CLI binary (
pino-pretty) that reads ndjson from stdin and writes formatted, colorized lines to stdout - A programmatic stream/transform (
require('pino-pretty')) usable directly as a Pino transport target or a plain writable stream - Automatic runtime adaptation to a logger’s custom levels and message key via Pino’s transport
PINO_CONFIGmessage channel - A
messageFormattemplating option (string or function) with conditional{if x}...{end}blocks for custom message layouts - Per-key
customPrettifiershooks to override how specific log properties (time, level, hostname, or arbitrary keys) are rendered - Config-file support (
.pino-prettyrc,pino-pretty.config.js) auto-discovered via joycon so CLI flags don’t need repeating
Common Use Cases
- Piping a Node.js app’s stdout through the CLI during local development for readable console logs
- Setting
transport: { target: 'pino-pretty' }in a Pino logger config so development logs are auto-formatted without touching app code - Filtering noisy fields with
--ignore/--includeto focus on the log keys that matter while debugging - Customizing error and object rendering with
customPrettifiersto surface domain-specific log fields (e.g. aqueryorreq.urlproperty) more usefully - Using
sync: truein test frameworks like Jest where async log flushing would otherwise race against test teardown
Under The Hood
Architecture
The entry point (index.js) exports a build() function that wraps the core formatter in a Node Transform stream via pino-abstract-transport, piped through pump to a destination (stdout, a file descriptor, or a sonic-boom instance built by the local buildSafeSonicBoom wrapper). The CLI (bin.js) parses argv with minimist, optionally loads a .pino-prettyrc config via joycon + secure-json-parse + strip-json-comments, merges it with CLI flags, and feeds the same build() entry point by piping process.stdin through it — so the CLI and the programmatic transport share one code path. The actual line-formatting logic lives in lib/pretty.js, which orchestrates roughly two dozen single-purpose modules under lib/utils/ (prettify-time, prettify-level, prettify-message, prettify-metadata, prettify-object, prettify-error-log, filter-log, interpret-conditionals, etc.), each doing one narrow transformation step. Options are parsed once into a shared context object (parse-factory-options.js) and bound to the pretty function via .bind(), avoiding per-line option re-parsing. This is a clean layered pipeline: stream/CLI plumbing, then formatting orchestration, then single-purpose utilities — changing the output format means editing lib/pretty.js’s assembly order and the relevant prettify-* module, without touching stream or CLI wiring.
Tech Stack
Plain CommonJS Node.js with no application framework. Dependencies are narrowly scoped: colorette for color-support detection and ANSI coloring, pump for safe stream piping/cleanup, pino-abstract-transport for the Pino v7+ transport contract, sonic-boom (wrapped locally) for fast async file/fd writes, dateformat for timestamp formatting, secure-json-parse/fast-safe-stringify/fast-copy for safe JSON handling, joycon + strip-json-comments for config-file discovery, minimist for CLI parsing, and help-me for rendering --help text from help/help.txt. Types are hand-authored in index.d.ts (JSDoc-driven, no source TypeScript). Linting uses neostandard (a StandardJS-based flat ESLint config); tests run on borp (Node’s native test runner) with c8 coverage gating in CI, plus tstyche for type-level tests and @arethetypeswrong/cli to verify the package’s dual CJS export shape resolves correctly for consumers. CI (.github/workflows/ci.yml) runs a Node 20/22/24 matrix against a pinned pino@^10 peer, plus a PR-only dependency-review gate. There is no database or deployment target — it’s a pure Node.js library and CLI.
Code Quality
Test coverage is unusually thorough for a project this size: nearly every file under lib/utils/ has a co-located *.test.js, and top-level suites (basic, boolean-options, cli, cli-rc, crlf, error-objects) exercise CLI behavior end-to-end in addition to unit-level formatter behavior. c8 coverage is enforced in the ci npm script (--check-coverage), and tstyche plus attw add type-level and package-export correctness tests that are unusually rigorous for a CommonJS package. Error handling favors defensive parsing over throwing: the core formatter wraps JSON parsing in a local try/catch and falls back to pass-through output on malformed input, while the CLI validates config-file shape and throws descriptive errors for invalid or missing rc files. Naming is consistent (kebab-case files, one narrowly-scoped export per file), and linting via neostandard is enforced in CI. No CONTRIBUTING.md was found at the repo root.
API Design
The public API is small and consistent: CLI flags and programmatic options share identical names (--colorize / colorize, --translateTime / translateTime, etc.), documented together in the README so switching between CLI and programmatic use requires no relearning. Getting started needs zero configuration — pino({ transport: { target: 'pino-pretty' } }) or a stdout pipe both work with sensible defaults (colorize based on TTY support, hostname ignored by default). Advanced customization (custom levels/colors, per-key customPrettifiers, a messageFormat mini-template language with {if x}...{end} conditionals) is opt-in and layered on top of the defaults rather than required up front. The transport integration goes further than a typical formatter: it listens for a PINO_CONFIG control message over the transport’s message channel to auto-adapt to a logger’s custom levels and message key at runtime, without any user-side wiring — a level of framework-specific integration generic ndjson-pretty-printers don’t attempt.
Used by 55 apps in this directory
HyperDX
Analytics · Developer Tools · Monitoring
Open source observability platform that unifies logs, traces, metrics, and session replays on ClickHouse — now the core of ClickStack.
Infisical
Devops · Security
The open-source platform for secrets, certificates, privileged access, and AI agent security — all in one self-hostable system.
Kan
Project Management
An open-source, self-hostable Kanban board built as a modern Trello alternative with team workspaces, board permissions, and Trello import.
ktx
AI Development · Analytics · Data Engineering
ktx builds a self-improving context layer over your data warehouse so AI agents like Claude Code and Codex query it with approved metric definitions instead of reinventing SQL logic from scratch.
LLM Gateway
AI Development · Devops
One API endpoint for 25+ LLM providers — route, track costs, enforce compliance, and switch models without changing your code.
Mastodon
Social Media
Run your own federated social network on the open ActivityPub standard with no ads, no algorithms, and no corporate control over your community.
Mastra Code
AI Code Assistants
"A coding agent that never compacts" — a terminal-based AI coding agent built on the Mastra framework, with Observational Memory instead of context compaction, multi-model support, and OAuth login for Claude Max or ChatGPT Plus.
MentraOS
AI Development · Developer Tools
The open source operating system and SDK that lets developers build one app and run it across smart glasses from Even Realities, Vuzix, Mentra Live, and more.
Midday
Invoicing Finance · Productivity
All-in-one AI-powered business operations platform for freelancers and solo entrepreneurs to manage invoicing, time tracking, banking, and financial intelligence.