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 53 apps in this directory
authentik
Authentication · Security
The self-hosted Identity Provider that replaces Okta, Auth0, and Entra ID with a unified SSO platform supporting SAML, OAuth2/OIDC, LDAP, RADIUS, and WebAuthn.
Blinko
Knowledge Management · Note Taking
A self-hosted, AI-powered card note-taking tool that lets you capture fleeting thoughts instantly and retrieve them with natural language search.
BrowserOS
Browser · AI Assistants
The open-source agentic Chromium browser with native AI agents, MCP server, and visual workflow automation — your data never leaves your machine.
Budibase
Low Code Platforms · No Code Platforms
Build AI agents, automations, and internal apps on a single open-source platform with full self-hosting control.
Bun
Developer Tools
An all-in-one JavaScript and TypeScript toolkit — one Rust-and-JavaScriptCore binary that replaces Node.js, npm, a bundler, and a test runner with faster equivalents.
Digger
Devops · Automation · Developer Tools
Run Terraform and OpenTofu natively inside your existing CI pipeline — no separate runners, no third-party secrets, no extra compute costs.
Directus
CMS · Low Code Platforms
Connect any SQL database and get instant REST and GraphQL APIs, a visual management Studio, and a native MCP server for AI agents — free for most organizations.
Dittofeed
Marketing · Automation
Open-source omni-channel customer engagement platform for automating transactional and marketing messages via email, SMS, WhatsApp, Slack, and mobile push.
Docmost
Productivity · Note Taking · Collaboration
Self-hosted collaborative wiki and knowledge base with real-time editing, diagrams, AI assistance, and enterprise access controls — a modern alternative to Confluence and Notion.