Winston was the go-to Node.js logger for years. But Pino is 5x faster — and here is why performance-focused teams are switching.
Why Pino is Faster
Pino logs as NDJSON (newline-delimited JSON) with minimal overhead. No synchronous operations, no string formatting in the hot path. Just fast, structured JSON.
Winston: ~10,000 ops/sec
Pino: ~52,000 ops/sec
Quick Start
bun add pino pino-pretty
import pino from "pino";
const logger = pino({ level: "info" });
logger.info("Server started");
logger.info({ port: 3000 }, "Listening on port");
logger.error({ err: new Error("DB failed") }, "Database connection error");
logger.warn({ userId: "123", action: "login_failed" }, "Authentication failed");
Output:
{"level":30,"time":1711800000000,"msg":"Server started"}
{"level":30,"time":1711800000001,"port":3000,"msg":"Listening on port"}
Pretty Printing (Development)
# Pipe through pino-pretty
node app.js | pino-pretty
// Or configure in code (dev only!)
const logger = pino({
transport: {
target: "pino-pretty",
options: { colorize: true, translateTime: "SYS:standard" }
}
});
Child Loggers
const logger = pino();
// Create child logger with bound context
const requestLogger = logger.child({ requestId: "abc-123" });
requestLogger.info("Processing request"); // includes requestId in every log
const userLogger = requestLogger.child({ userId: "user_456" });
userLogger.info("User action"); // includes both requestId AND userId
With Express/Fastify
// Express
import pinoHttp from "pino-http";
app.use(pinoHttp());
// Fastify (built-in!)
const fastify = Fastify({ logger: true });
// That is it — Fastify uses Pino natively
Log Redaction (Hide Sensitive Data)
const logger = pino({
redact: {
paths: ["password", "creditCard", "req.headers.authorization"],
censor: "[REDACTED]"
}
});
logger.info({ user: "alice", password: "secret123" }, "Login attempt");
// Output: {"user":"alice","password":"[REDACTED]","msg":"Login attempt"}
Transport (Send Logs Anywhere)
const logger = pino({
transport: {
targets: [
{ target: "pino-pretty", level: "info", options: { destination: 1 } },
{ target: "pino/file", level: "error", options: { destination: "./errors.log" } },
{ target: "pino-elasticsearch", level: "info", options: { index: "app-logs" } }
]
}
});
Pino vs Winston vs Bunyan
| Feature | Pino | Winston | Bunyan |
|---|---|---|---|
| Speed | 52K ops/s | 10K ops/s | 8K ops/s |
| Output | NDJSON | Flexible | JSON |
| Child Loggers | Yes | Yes | Yes |
| Redaction | Built-in | Plugin | No |
| Pretty Print | pino-pretty | Built-in | bunyan CLI |
| Transports | Worker thread | Sync | Streams |
| Fastify | Native | Plugin | Plugin |
Building logging for scraping pipelines? Check out my web scraping actors on Apify Store — production-ready with structured logging. For custom solutions, email spinov001@gmail.com.
Top comments (0)