Forward Pino logs to LogFlow using a destination stream. Keep your existing Pino setup and get structured search, alerts, and anomaly detection on top.
Pino is the fastest Node.js logger — used by Fastify, NestJS, and high-throughput services. The LogFlow Pino integration works as a destination stream, so Pino continues writing JSON at full speed and LogFlow picks it up automatically.
pino v6, v7, v8, or v9)npm install @getlogflow/js
import pino from 'pino'
import { createLogFlowStream } from '@getlogflow/js/transports/pino'
const logger = pino(
{ level: 'info' },
createLogFlowStream({
apiKey: process.env.LOGFLOW_API_KEY!,
service: 'api', // rename to your service
environment: process.env.NODE_ENV,
release: process.env.APP_VERSION, // optional
})
)
export default logger
Add your API key to .env:
LOGFLOW_API_KEY=lf_your_api_key_here
Pino encourages putting data in the first object and the message second:
logger.info({ userId: 'u_123', plan: 'starter' }, 'User signed up')
logger.warn({ ip: req.ip, limit: 100 }, 'Rate limit approaching')
logger.error({ err, orderId: 'ord_456' }, 'Payment failed')
All fields are preserved in LogFlow as searchable attributes.
In development you likely want Pino to print to stdout while also sending to LogFlow:
import pino from 'pino'
import pinoPretty from 'pino-pretty'
import { createLogFlowStream } from '@getlogflow/js/transports/pino'
const isDev = process.env.NODE_ENV !== 'production'
const logger = isDev
// Development: pretty print to console only
? pino({ level: 'debug' }, pinoPretty())
// Production: send to LogFlow
: pino(
{ level: 'info' },
createLogFlowStream({ apiKey: process.env.LOGFLOW_API_KEY!, service: 'api' })
)
Or use pino-multi-stream to send to both simultaneously:
import pino from 'pino'
import { multistream } from 'pino-multi-stream'
import { createLogFlowStream } from '@getlogflow/js/transports/pino'
const logger = pino(
{ level: 'info' },
multistream([
{ stream: process.stdout },
{ stream: createLogFlowStream({ apiKey: process.env.LOGFLOW_API_KEY!, service: 'api' }) },
])
)
Fastify has built-in Pino support. Pass the LogFlow stream as Fastify's logger:
import Fastify from 'fastify'
import { createLogFlowStream } from '@getlogflow/js/transports/pino'
const app = Fastify({
logger: {
level: 'info',
stream: createLogFlowStream({
apiKey: process.env.LOGFLOW_API_KEY!,
service: 'api',
environment: process.env.NODE_ENV,
}),
},
})
// Fastify's built-in request logging now goes to LogFlow
app.get('/users/:id', async (request, reply) => {
request.log.info({ userId: request.params.id }, 'Fetching user')
// ...
})
Fastify automatically logs every request with method, url, status, and response time.
Add a traceId to all logs from a single request using Pino's child logger:
app.addHook('onRequest', async (request) => {
request.traceId = request.headers['x-trace-id'] || crypto.randomUUID()
request.log = request.log.child({ traceId: request.traceId })
})
In LogFlow, click View trace to see the entire request flow grouped by traceId.
Restart your app and make a request. Open LogFlow → Live Tail — logs appear within a few seconds.
Does this affect Pino's performance? The stream writes are synchronous from Pino's side. The actual HTTP requests to LogFlow happen asynchronously in the background, so there's no blocking.
What if LogFlow is down? Logs are queued in memory and retried automatically. If the queue fills up (default 1000 logs), the oldest are dropped.
Pino levels vs LogFlow levels
Pino numeric levels map to LogFlow as follows: 10 (trace) → trace, 20 → debug, 30 → info, 40 → warn, 50 → error, 60 → fatal.
Free plan available. No credit card required. Up and running in 2 minutes.
Get started freeWinston Logging Integration
Plug LogFlow into an existing Winston setup without changing your application code.
Add Logging to a Next.js App
Set up LogFlow in a Next.js project — capture server errors, API route logs, and frontend exceptions in under 15 minutes.
Structured Logging in Express.js
Add production-ready structured logging to any Express.js app in under 10 minutes.