Frequently Asked Questions (FAQ)
Common questions and answers about @nextrush/log.
Installation & Setup
How do I install @nextrush/log?
npm install @nextrush/log
# or
pnpm add @nextrush/log
# or
yarn add @nextrush/log
# or
bun add @nextrush/logDoes it work with TypeScript?
Yes! Full TypeScript support with complete type definitions included. No additional @types package needed.
What runtimes are supported?
| Runtime | Supported | Notes |
|---|---|---|
| Node.js | ✅ | v18+ (engines in package) |
| Bun | ✅ | Full support |
| Deno | ✅ | Use npm: specifier |
| Browser | ✅ | Works in all modern browsers |
| React | ✅ | Dedicated hooks and providers |
| Next.js | ✅ | Client and server components |
| Edge (Cloudflare/Vercel) | ✅ | Zero Node.js dependencies |
How do I use it in Deno?
import { createLogger } from 'npm:@nextrush/log';
const log = createLogger('MyApp');
log.info('Works in Deno!');Global Configuration
How do I disable ALL logging with one line?
import { disableLogging } from '@nextrush/log';
disableLogging(); // Done! All loggers are silent.If I have 400+ files using createLogger, do I need to change them all?
No! Global configuration is a singleton - configure once, affects all files:
// src/lib/logger.ts - Configure ONCE
import { configure } from '@nextrush/log';
configure({ enabled: false }); // Affects ALL 400+ files!All other files just use createLogger() normally - they automatically respect global config.
Where should I call configure() or disableLogging()?
At your app's entry point, before other code runs:
| App Type | Where to Configure |
|---|---|
| Node.js | src/index.ts or src/main.ts |
| React/Vite | src/main.tsx (before <App />) |
| Next.js | _app.tsx or root layout.tsx |
| Express | Before app.listen() |
What if multiple files import configure?
Importing doesn't call the function. Only the file that calls configure() changes settings. It's safe to import everywhere.
How do I reset configuration to defaults?
There's no dedicated resetGlobalConfig() on the public main barrel — call configure() with the factory defaults you care about (this is also more explicit about what's actually being reset):
import { configure } from '@nextrush/log';
configure({
enabled: true,
silent: false,
enabledNamespaces: ['*'],
disabledNamespaces: [],
defaults: {},
});If you're writing tests and want full isolation between test files, prefer creating an isolated logger per test (createLogger(name, options)) over resetting shared global state.
Log Levels
What are the available log levels?
| Level | Internal priority | Use case |
|---|---|---|
trace | 0 | Very chatty diagnostics |
debug | 1 | Development detail |
info | 2 | Normal operations (typical prod default) |
warn | 3 | Something wrong, app continues |
error | 4 | Failures |
fatal | 5 | Worst-case failures |
How does level filtering work?
Only levels at or above minLevel are emitted (see log levels):
const log = createLogger('App', { minLevel: 'warn' });
log.debug('ignored');
log.info('ignored');
log.warn('logged');
log.error('logged');How does configure({ minLevel }) interact with per-logger minLevel?
The stricter wins: a logger created with minLevel: 'error' will not start logging at info when the global floor is trace. To drop only the global floor and keep per-logger rules, call configure({ minLevel: undefined }).
How do I change log level at runtime?
const log = createLogger('App');
// Change level dynamically
log.setLevel('error'); // Now only error + fatal
// Check before expensive operations
if (log.isLevelEnabled('debug')) {
log.debug('Data', computeExpensiveData());
}Why are my debug logs not showing in production?
By default, production (NODE_ENV=production) uses minLevel: 'info'. Debug and trace are filtered out.
To enable debug logs in production:
const log = createLogger('App', {
env: 'production',
minLevel: 'debug', // Override the default
});Environment & Production
How does environment detection work?
The logger reads NODE_ENV automatically:
| NODE_ENV | minLevel | Output | Redaction |
|---|---|---|---|
development | trace | Pretty | Off |
test | trace | Pretty | Off |
production | info | JSON | On |
Why are my debug logs showing in Vite production build?
Vite uses import.meta.env.MODE instead of NODE_ENV. Force production mode:
const log = createLogger('App', {
env: 'production' // Force production mode
});
// Or configure globally
configure({ env: 'production' });How do I get JSON output?
Set pretty: false or use env: 'production':
const log = createLogger('App', { pretty: false });
// OR
const log = createLogger('App', { env: 'production' });How do I get colorful output in production?
const log = createLogger('App', {
env: 'production',
pretty: true, // Override JSON output
colors: true, // Enable colors
});Sensitive Data
What fields are automatically redacted?
By default in production, these fields are redacted:
password,passwd,pwdtoken,accessToken,refreshTokensecret,apiKey,apiSecretauthorization,authcookie,sessioncreditCard,cardNumber,cvvssn,socialSecurity
How do I add custom sensitive fields?
const log = createLogger('App', {
sensitiveKeys: ['customSecret', 'myApiKey', 'internalToken'],
});How do I disable redaction?
const log = createLogger('App', { redact: false });WARNING
Never disable redaction in production - sensitive data will be logged!
Does redaction work in nested objects?
Yes! Redaction is recursive:
log.info('Data', {
user: {
name: 'John',
auth: {
password: 'secret123', // → "[REDACTED]"
},
},
});Child Loggers
What is a child logger?
A child logger inherits parent settings and adds a namespace prefix:
const log = createLogger('App');
const db = log.child('Database');
const api = log.child('API');
db.info('Connected'); // [App:Database] Connected
api.info('Ready'); // [App:API] ReadyDo child loggers respect global config?
Yes! Child loggers inherit global configuration just like parent loggers.
Can I create deeply nested children?
Yes:
const log = createLogger('App');
const api = log.child('API');
const users = api.child('Users');
const create = users.child('Create');
create.info('User created'); // [App:API:Users:Create] User createdPerformance
Is logging expensive?
Logging is designed to be cheap:
- Level checks are fast (number comparison)
- Disabled logs are no-ops (almost zero cost)
- Serialization only happens for enabled logs
How do I avoid expensive computations for disabled logs?
// ❌ Bad: Always computes even if debug is disabled
log.debug('Data', { result: expensiveComputation() });
// ✅ Good: Only compute if level is enabled
if (log.isLevelEnabled('debug')) {
log.debug('Data', { result: expensiveComputation() });
}How do I measure performance?
const timer = log.time('db-query');
const result = await db.query('SELECT * FROM users');
timer.end('Query done', { rows: result.length });
// Output: "Query done" { duration: 42, rows: 150 }Transports
What is a transport?
A transport is a function that receives log entries and does something with them (e.g., send to a server, write to file).
const myTransport = (entry) => {
fetch('/api/logs', {
method: 'POST',
body: JSON.stringify(entry),
});
};
const log = createLogger('App');
log.addTransport(myTransport);What is a global transport?
A global transport receives logs from ALL loggers in your app:
import { addGlobalTransport } from '@nextrush/log';
addGlobalTransport((entry) => {
if (entry.level === 'error') {
sendToSentry(entry);
}
});How do I batch logs before sending?
Use createBatchTransport:
import { createBatchTransport } from '@nextrush/log';
const { transport, flush } = createBatchTransport(
async (logs) => {
await fetch('/api/logs', {
method: 'POST',
body: JSON.stringify(logs),
});
},
{ batchSize: 50, flushInterval: 5000 }
);
const log = createLogger('App');
log.addTransport(transport);
// Flush before shutdown
process.on('SIGTERM', async () => {
await flush();
process.exit(0);
});React & Browser
How do I use in React?
import { LoggerProvider, useLogger } from '@nextrush/log/react';
function App() {
return (
<LoggerProvider context="MyApp" options={{ minLevel: 'debug' }}>
<MyComponent />
</LoggerProvider>
);
}
function MyComponent() {
const log = useLogger('MyComponent');
return <button onClick={() => log.info('Clicked!')}>Click</button>;
}How do I disable logging in React production builds?
<LoggerProvider
context="MyApp"
globalConfig={{
enabled: process.env.NODE_ENV !== 'production',
}}
>
{children}
</LoggerProvider>Does it work with Next.js App Router?
Yes! Works in both client and server components:
// Server Component
import { createLogger } from '@nextrush/log';
const log = createLogger('ServerComponent');
// Client Component
'use client';
import { useLogger } from '@nextrush/log/react';How do I see logs in browser DevTools?
Logs automatically go to browser console. Use DevTools → Console tab.
Namespace Filtering
How do I log only from specific modules?
import { configure, createLogger } from '@nextrush/log';
// Only log from api and auth
configure({ enabledNamespaces: ['api:*', 'auth:*'] });
createLogger('api:users').info('Logged'); // ✅
createLogger('db:queries').info('Ignored'); // ❌What patterns are supported?
| Pattern | Matches |
|---|---|
* | Everything |
api:* | api:users, api:auth, api:orders:create |
auth:login | Only auth:login (exact) |
How do I disable specific namespaces?
import { configure } from '@nextrush/log';
configure({
enabledNamespaces: ['*'], // Enable everything
disabledNamespaces: ['verbose:*'], // Except verbose
});Troubleshooting
My logs are not appearing
Check log level:
typescriptconst log = createLogger('App'); console.log(log.isLevelEnabled('debug')); // false if level too highCheck namespace filtering:
enabledNamespaces/disabledNamespacesare write-only from the public API — there's no exported getter for the resolved namespace state. Narrow it down by trying the log call directly instead:typescriptconst log = createLogger('your:namespace'); log.info('probe'); // if this is silent, the namespace is filtered outCheck global config didn't disable everything:
configure()is set-only too — there's no publicgetGlobalConfig(). If you suspect a strayconfigure({ enabled: false })ordisableLogging()call ran somewhere, grep for it, or callconfigure({ enabled: true })explicitly to rule it out.typescriptimport { configure } from '@nextrush/log'; configure({ enabled: true, minLevel: 'trace' });
My logs are showing "[REDACTED]"
Redaction is on (usually in production). Either:
- Check you're not logging sensitive fields unintentionally
- Disable redaction for development:
{ redact: false }
TypeError: createLogger is not a function
Check your import:
// ✅ Correct
import { createLogger } from '@nextrush/log';
// ❌ Wrong
import createLogger from '@nextrush/log';React: useLogger must be used within LoggerProvider
Wrap your app with LoggerProvider:
function App() {
return (
<LoggerProvider context="App">
{/* Your components here */}
</LoggerProvider>
);
}Logs are appearing twice
You might have added the same transport twice, or have both console transport and pretty: true. Check your transports:
const log = createLogger('App');
console.log(log); // Inspect transports arrayArchitecture & Design
Why singleton pattern instead of DI?
Logging is a cross-cutting concern used everywhere in an application. The singleton pattern:
- Simplicity - No need to pass logger through every function
- Industry standard - Winston, Pino, Bunyan all use singletons
- Testability - isolated
createLogger()instances per test avoid global state entirely - Performance - No DI container overhead
Is it tree-shakeable?
Yes! Import only what you need:
// Only imports createLogger, not global config functions
import { createLogger } from '@nextrush/log';Does it have any dependencies?
Zero dependencies. The entire library is self-contained.
Is it safe to use in serverless/edge?
Yes! Designed for:
- Cloudflare Workers
- Vercel Edge Functions
- AWS Lambda@Edge
- Deno Deploy
No file system or Node.js-specific APIs required.
Migration
Migrating from console.log
// Before
console.log('User created:', userId);
// After
import { createLogger } from '@nextrush/log';
const log = createLogger('App');
log.info('User created', { userId });Migrating from Winston
// Winston
const winston = require('winston');
const logger = winston.createLogger({ level: 'info' });
logger.info('Hello', { user: 'john' });
// @nextrush/log
import { createLogger } from '@nextrush/log';
const log = createLogger('App', { minLevel: 'info' });
log.info('Hello', { user: 'john' });Migrating from Pino
// Pino
const pino = require('pino');
const logger = pino({ level: 'info' });
logger.info({ user: 'john' }, 'Hello');
// @nextrush/log (data comes last)
import { createLogger } from '@nextrush/log';
const log = createLogger('App', { minLevel: 'info' });
log.info('Hello', { user: 'john' });