How to Remove console.log in Production (and What to Use Instead)
console.log is the fastest way to debug JavaScript, which is exactly why so many of them end up in production. In the browser they expose internal data to anyone who opens DevTools. On the server they produce unstructured output that is hard to search. Here is how to stop them reaching production and what to log with instead.
Why leftover console.log is a problem
- Data exposure: tokens, user records, and API responses printed to the browser console are visible to anyone
- Noise: real warnings get buried under debug output
- Performance: logging large objects in hot paths or loops costs time and memory, and keeps objects alive for DevTools
- Unstructured server logs: plain strings cannot be filtered by user, request, or level
Step 1: stop new ones with ESLint
export default [
{
rules: {
'no-console': ['error', { allow: ['warn', 'error'] }]
}
}
];
Step 2: strip them from production builds
Dropping all console calls also removes console.error. If you rely on it for error reporting, use Terser's pure_funcs option to drop only console.log and console.debug.
// vite.config.js
export default defineConfig(({ mode }) => ({
esbuild: mode === 'production' ? { drop: ['console', 'debugger'] } : {}
}));
new TerserPlugin({
terserOptions: { compress: { drop_console: true } }
});
Step 3: use a real logger
On Node.js, a structured logger such as pino or winston writes JSON with levels and fields, so you can search by request ID or user. In the browser, send errors to an error-tracking service instead of the console.
import pino from 'pino';
const logger = pino({ level: process.env.LOG_LEVEL ?? 'info' });
logger.info({ orderId, userId }, 'Order placed');
logger.error({ err, orderId }, 'Payment failed');
Find the ones already in your code
CodeInspector reports console logging in JavaScript as rule JS0007 with the file and line, so you can clean up what ESLint never saw in older code. Scan a repository at https://codeinspector.app with 100 free credits.