Where does Node.js store application logs?

Find stdout and stderr logs under shell redirection, PM2, systemd, or containers, and choose a structured logging and retention strategy.

Best practices
Application troubleshooting illustration

Node.js does not choose one default application log file. console.log() writes to stdout and console.error() writes to stderr. The terminal, shell, process manager, or container runtime determines where those streams go and how long they are retained.

Stopping the Node process does not necessarily erase its previous output. It may remain in terminal scrollback, a redirected file, a journal, or a centralized logging system.

Redirect output from the shell

node app.js > app.log 2>&1
# Append instead of replacing the file:
node app.js >> app.log 2>&1
# Keep the streams separate:
node app.js >> app.log 2>> error.log

These are alternative launch commands. > truncates an existing file; >> appends. In a POSIX-style shell, 2>&1 directs stderr to stdout's current destination, so redirection order matters. The shell does not add timestamps or rotate these files automatically.

Check the process manager

Environment Where to start
PM2 pm2 logs and the configured log paths; defaults are normally under ~/.pm2/logs
systemd journalctl -u YOUR_SERVICE, when the unit sends output to the journal
Docker docker logs CONTAINER, depending on the configured logging driver
Kubernetes kubectl logs POD; use --previous for an available previous container instance

PM2's home directory and individual output/error paths are configurable. Log rotation requires an appropriate policy, such as a configured pm2-logrotate module; it is not implied merely by using PM2. Journal and container retention also depend on host and runtime settings. Kubernetes container logs are not a permanent archive, so collect them elsewhere when longer retention is needed.

Emit structured application logs

A logging library such as Pino or Winston can provide levels, structured fields, and configurable destinations. For example, after installing Pino:

const pino = require('pino');
const logger = pino({ level: process.env.LOG_LEVEL || 'info' });
logger.info({ service: 'checkout', requestId: 'example-42' }, 'Request started');
const error = new Error('Example downstream failure');
logger.error({ err: error, requestId: 'example-42' }, 'Request failed');

Pino's default output is JSON on stdout. Configure sensitive-field redaction and avoid logging credentials or entire request bodies by default. Request IDs help follow one request; trace IDs can connect logs with traces when the application actually supplies compatible tracing context. A logging library alone does not create that integration.

Choose collection and retention deliberately

For containerized services, emitting structured logs to stdout allows the runtime and collector to handle transport and storage. File-based deployments can work too, but need rotation, permissions, storage limits, and a collection policy. Avoid storing multiple uncontrolled copies of the same stream.

Guance supports log collection. Configure the collector for the application's actual destination and verify parsed fields before relying on searches or alerts.

Can logging slow the application? Yes. Formatting, serialization, transport, and destination behavior all contribute. Node's stdout and stderr can write synchronously or asynchronously depending on the platform and destination. Measure realistic volume and use bounded transport behavior rather than assuming every logger is nonblocking.

See Node process I/O, PM2 log management, and Pino's API.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting