ShipReady Guide · Launch polish · Next.js · Vite

How to Remove console.log From Production (Next.js and Vite)

AI-generated code is full of console.log calls left over from debugging. In production they print user objects, API responses and tokens to anyone who opens devtools, and a stray debugger statement can freeze the page. Here's how to strip them at build time.

5-minute readUpdated Oct 2026All guides

The short version

  • Find them: one search across src/ shows how many you have.
  • Strip at build time: Next.js has a compiler option; Vite can drop them during the build.
  • Keep real errors: drop console.log and debugger, keep console.error.
  • Stop new ones: a lint rule catches them before they ship.

1. Why it matters

  • Data leaks. Logging a whole user or API response prints emails, IDs and sometimes tokens for anyone with devtools open.
  • It looks unfinished. Developers who check out your launch will open the console.
  • debugger statements pause the page for any visitor with devtools open.

2. Find what you have

Count debug statements in your source
grep -rnE "console\.log|debugger" src app components --include=*.{js,jsx,ts,tsx} | wc -l

Remove anything that logs secrets or whole user objects by hand, since those also show up in server logs. Then let the build strip the rest.

3. Next.js: the removeConsole option

Next.js can remove console calls from your application code during the build. Keep errors and warnings so real problems still surface:

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  compiler: {
    removeConsole:
      process.env.NODE_ENV === "production"
        ? { exclude: ["error", "warn"] }
        : false,
  },
};

module.exports = nextConfig;

4. Vite: drop at build time

On Vite versions that use esbuild for transforms, drop console and debugger only for production builds:

vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig(({ command }) => ({
  plugins: [react()],
  esbuild:
    command === "build"
      ? { drop: ["debugger"], pure: ["console.log", "console.debug"] }
      : {},
}));

pure removes only the listed calls, so console.error survives. If your Vite version uses a different transformer, check its build docs for the equivalent drop option; the lint rule below works on every version.

5. Stop new ones with a lint rule

eslint.config.js (add to your rules)
rules: {
  "no-console": ["warn", { allow: ["error", "warn"] }],
  "no-debugger": "error",
}

For logging you actually need in production, use console.error for real failures or an error tracker like Sentry, which captures context without printing it to every visitor.

Before you ship

  • No console.log calls print user data, tokens or full API responses.
  • The production build strips console.log and debugger.
  • console.error still reports real failures.
  • A lint rule flags new debug logging.

Check your live site in 60 seconds

ShipReady scans your deployed URL and the JavaScript visitors actually download: leaked keys, Supabase exposure, unprotected API routes, titles and share images. Secret findings unlock only after you verify you own the site.

Free scan, no signup, no code upload.

FAQ

Some console messages are still there after the build. Why?

Build options usually only strip your application code, not third-party packages. A few library messages are normal. What matters is that your own debug output is gone.

Is console.log a security vulnerability?

Not by itself. It becomes one when it prints secrets, tokens or other users' data, which AI-generated debug code often does.

Keep reading

Sources: Next.js: compiler options (removeConsole) · ESLint: no-console rule