Skip to main content
Pino is the recommended logger provider: extremely fast structured JSON output in production, with optional pino-pretty colorised formatting for local dev.

The LoggerType interface

Every logger provider satisfies the same contract, so all log calls work identically regardless of which provider is active:
type LoggerType = {
  info: (message: string, meta?: Record<string, unknown>) => void;
  warn: (message: string, meta?: Record<string, unknown>) => void;
  error: (error: unknown, meta?: Record<string, unknown>) => void;
  getFeatureLogger: (feature: string) => FeatureLoggerType;
};
getFeatureLogger creates a child logger scoped to a named feature. Pino implements this as a true child logger with { feature } bound and a duration field (ms since the child was created) appended to every line:
const ftLogger = tools.logger.getFeatureLogger('subscriptionUpgrade');
ftLogger.info('Starting upgrade', { organizationId });
// ... do work ...
ftLogger.info('Upgrade complete', { plan });
// Both lines include: { feature: 'subscriptionUpgrade', duration: 42.3 }
Use getFeatureLogger for any operation that spans multiple log lines — it makes log correlation trivial in aggregators.

Why

Pino is one of the fastest Node.js loggers available — it serialises log lines to JSON with minimal overhead and integrates cleanly with log aggregators like Datadog, Logtail, or CloudWatch. The pretty: true flag activates pino-pretty for colorised, human-readable output during local development, while production stays machine-parseable JSON.

Setup

  1. In apps/backend/package.json, ensure "tooling-logger-pino": "workspace:*" is listed under dependencies.
  2. Run make pnpm-lockfile-update then make pnpm-install.
  3. In development.ts, set tools.logger:
    logger: {
      client: LoggerClientType.PINO,
      pretty: true,
    }
    
  4. In production.ts, set tools.logger:
    logger: {
      client: LoggerClientType.PINO,
      pretty: false,
    }
    
  5. Run make test module=tooling-logger-pino and make test module=backend.

Log levels

MethodWhen to use
logger.info(message, meta)Successful operations, important lifecycle events
logger.warn(message, meta)Expected failures, business-rule violations, degraded states
logger.error(error, meta)Unexpected exceptions, system failures

Gotchas

  • pretty: true requires pino-pretty to be installed. It is a dependency of tooling-logger-pino, so it’s available automatically.
  • Pino serialises log arguments asynchronously in a worker thread. Very high-frequency logging (> 100k lines/sec) can cause slight buffering — this is normal.
  • Never set pretty: true in test.ts — it adds noise to test output. Leave it false or omit it entirely.

What’s next?

  • Console — the minimal fallback provider.
  • Configuration — switching pluggable tool implementations.
  • Tooling system — how loaders and workspace packages fit together.