mrkeyoor.com_
Wed 23 Sept 00:35 UTC
npmInfraupdated 22 Sept 2026

bunyan review

Bunyan 1.8.15 turns each Node.js log call into one JSON line with fixed fields for the logger name, host, process, level, message, timestamp, and record version. The package also supplies a terminal formatter, child loggers for bound context, serializers for Error and HTTP objects, and stream routing by level. The current release teaches the request serializer to read Express `originalUrl`; its other stated change replaces the obsolete nodeunit test runner with node-tap 9. This remains a CommonJS, Node-focused logger rather than a browser logging package.

Verdict

Bunyan 1.8.15 took 9.4 seconds and 8 MB in our sandbox, emitted 3 deprecation warnings, and failed the browser bundle, so keep it for established Node log pipelines rather than choosing it for a new project. Its JSON record format and CLI still do their jobs, but the January 2021 latest release and missing bundled types are real costs.

We installed it

Lab card: what happened when we installed bunyanScreenshot of bunyan documentation
Install✓ · 9.4s21 packages on disk · 8 MB · 3 deprecation warnings
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does bunyan install cleanly?

Yes. In a fresh container with an empty cache, npm install bunyan finished in 9 seconds, leaving 21 packages and 8 MB on disk. npm audit reported no known vulnerabilities. The install printed 3 deprecation warnings.

Can bunyan run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does bunyan work with both ESM and CommonJS?

Yes. Both import 'bunyan' and require('bunyan') worked in Node 22 in our run. The package is published as CommonJS.

Does bunyan include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

bunyan or pino: which should you use?

pino: Choose it for a new Node service where low logging overhead and active releases matter. Bunyan 1.8.15 took 9.4 seconds and 8 MB in our sandbox, emitted 3 deprecation warnings, and failed the browser bundle, so keep it for established Node log pipelines rather than choosing it for a new project.

When should you not use bunyan?

You are picking a logger for new Node code: npm's latest tag still points to 1.8.15 from January 2021, while 2.0.5 remains on the beta tag

API stability5/5Bunyan 1.x keeps the same `createLogger`, six level methods, child logger, serializer, and stream descriptor model documented across the README and changelog. Release 1.8.15 changes how the request serializer finds an Express URL without replacing the public logging contract. The README says the project follows semantic versioning and reserves breaking work for a major release. That is strong compatibility evidence, though the long quiet period also means stability partly comes from limited change.
Docs4/5The repository README defines the JSON record fields, level numbers, logger call signatures, serializers, stream types, CLI filters, child behavior, DTrace support, and rotation limits. It directly warns about the cost of `src`, file descriptors after external rotation, and clustered writers sharing a rotating file. Those operational details are better than a short API reference. Examples still use old Node conventions, and the docs do not give a current TypeScript or modern ESM path.
Maintenance2/5npm published 1.8.15 on January 8, 2021, and GitHub reports the repository's last push on September 18, 2023. The README still places 2.x behind a beta tag while npm installs 1.x by default. GitHub currently reports 291 open issues and pull requests combined, and the repository is not archived. The package may be stable enough for existing deployments, but these dates do not support an active-maintenance claim for a new dependency choice.
Ecosystem4/5The npm endpoint recorded 3,998,507 Bunyan downloads for the week ending August 24, 2026, and GitHub reports 7,208 stars. The package has a matching CLI, a documented third-party stream interface, and community TypeScript declarations outside the package. That installed base makes old deployments serviceable. New Node logging work is more likely to start with Pino or Winston, so Bunyan's reach should be read as compatibility demand rather than current direction.

Use it if

  • An existing service or log collector already depends on Bunyan's newline-delimited record shape
  • You want raw JSON in production and the matching `bunyan` CLI for local filtering and readable output
  • Request IDs, tenant IDs, or component names should be attached once through child loggers
  • Different severity levels need to flow to separate Node writable streams
Skip it if

Setup reality

Our Bunyan 1.8.15 install completed in 9.4 seconds in a fresh Node 22 container. It left 21 packages using 8 MB on disk and printed 3 deprecation warnings. npm audit reported 0 known vulnerabilities. The installed package itself was 224 KB unpacked, exposed 0 peer dependencies, and our measurement recorded 0 direct dependencies.

Both require('bunyan') and ESM import loaded the CommonJS package, but there is no exports map and no bundled TypeScript declaration. TypeScript users need @types/bunyan. A logger must have a name; without an explicit stream it writes JSON to stdout at info level. Use the CLI only to format or filter that JSON for people.

Configure bunyan.stdSerializers before expecting useful err, req, or res fields. The HTTP serializers leave bodies out, but they do not promise to scrub headers. Version 1.8.15 now reads Express req.originalUrl. Avoid src: true on a hot path because the README calls source discovery slow.

Built-in file rotation is time based and cannot coordinate several processes sharing one path. If an external rotator renames a log file, call reopenFileStreams() after rotation or Bunyan keeps the old descriptor. Stream failures arrive as EventEmitter error events, so file-backed loggers need an error listener. Our browser bundle attempt failed, which confirms this package belongs in Node services.

Patterns

Write JSON records to stdout create-logger

const bunyan = require('bunyan');

const log = bunyan.createLogger({ name: 'orders-api' });
log.info('service started');

`name` is mandatory. With no stream list, version 1.8.15 emits info-and-higher JSON records to stdout.

Attach fields without colliding with the record add-fields

log.info({
  orderId: 'ord_123',
  totalCents: 2499
}, 'order accepted');

Put a domain object under a named property. Bunyan merges the first object into the record, so arbitrary keys can overwrite reserved fields.

Serialize an Error with context log-error

const log = bunyan.createLogger({
  name: 'worker',
  serializers: bunyan.stdSerializers
});

try {
  await runJob();
} catch (err) {
  log.error({ err, jobId: 'job_42' }, 'job failed');
}

`stdSerializers.err` preserves the message, name, stack, and code that ordinary JSON serialization can lose from an Error.

Bind a request ID to a child child-context

function requestLogger(requestId) {
  return log.child({ requestId });
}

requestLogger('req_7').info({ path: '/orders' }, 'received');

Every child call includes `requestId`. Child bindings are a better fit than mutating a shared logger during concurrent requests.

Shape Node request and response objects http-serializers

const httpLog = bunyan.createLogger({
  name: 'http',
  serializers: bunyan.stdSerializers
});

httpLog.info({ req }, 'request received');
httpLog.info({ res }, 'response sent');

Version 1.8.15 reads Express `originalUrl`. The standard serializers omit bodies but can still include header data that your policy may require you to redact.

Route severe records to a file route-levels

const log = bunyan.createLogger({
  name: 'payments',
  streams: [
    { level: 'info', stream: process.stdout },
    { level: 'error', path: '/var/log/payments-error.log' }
  ]
});

A level is a minimum threshold, so error and fatal records go to both destinations in this 2-stream configuration.

Catch destination failures handle-stream-error

log.on('error', (err, stream) => {
  const target = stream.path || 'configured stream';
  process.stderr.write(`log write failed for ${target}: ${err.message}\n`);
});

A file-stream failure is an EventEmitter error, separate from calling `log.error()`. An unhandled `error` event can stop the process.

Skip expensive debug field creation guard-debug-work

if (log.debug()) {
  log.debug({ state: buildDebugState() }, 'worker state');
}

Calling a level method with no arguments returns whether that level is enabled, so filtered records do not require building their fields.

Read and filter Bunyan JSON filter-cli

node server.js | npx bunyan
node server.js | npx bunyan -l warn
npx bunyan app.log -c 'this.requestId == "req_7"'

The CLI formats existing newline-delimited records. Keep the raw JSON as the source consumed by production collectors.

Retain seven daily log files rotate-by-time

const log = bunyan.createLogger({
  name: 'batch',
  streams: [{
    type: 'rotating-file',
    path: '/var/log/batch.log',
    period: '1d',
    count: 7
  }]
});

The built-in stream rotates by time, not bytes. Several worker processes must not share this rotating path.

Reopen descriptors after logrotate reopen-file

process.on('SIGUSR2', () => {
  log.reopenFileStreams();
});

Call this after an external tool renames active files without copytruncate; otherwise Bunyan continues writing to the old descriptor.

Keep the latest trace records in memory ring-buffer

const ring = new bunyan.RingBuffer({ limit: 100 });
const log = bunyan.createLogger({
  name: 'worker',
  streams: [
    { level: 'info', stream: process.stdout },
    { level: 'trace', type: 'raw', stream: ring }
  ]
});

console.log(ring.records);

A raw stream receives JavaScript record objects. The `limit: 100` bound matters because retained records stay in process memory.

Alternatives

PackageRegistryPick it when
pinonpmChoose it for a new Node service where low logging overhead and active releases matter.
winstonnpmChoose it when transports and configurable output formats matter more than Bunyan's fixed record convention.
log4jsnpmChoose it for category-based configuration and log4j-style appenders.

More infra guides

boto3 · opentelemetry-api · psutil · distro · @opentelemetry/api · google-cloud-storage · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.