Debug mode controls whether Laravel shows a detailed error page (full stack trace, the exact query that failed, environment variable values in some cases) or a generic error page when something goes wrong.
Where it's set
# .env
APP_DEBUG=true # local development
APP_DEBUG=false # production, always
This is read by config/app.php's debug key, which defaults to env('APP_DEBUG', false) — so if the environment variable is ever missing entirely, Laravel falls back to false (safe by default), not true.
Why leaving it on in production is a real security issue
With debug mode on, an unhandled exception shows a full stack trace to anyone who triggers it — including file paths, the exact SQL query and bindings involved, and sometimes configuration values interpolated into error messages. This is genuinely useful information for an attacker probing for weaknesses, not just an ugly page.
Config caching interaction
If the app runs php artisan config:cache in production (recommended for performance), the cached config is what's actually used — changing APP_DEBUG in .env after caching has no effect until you run php artisan config:cache again. This is a common reason people think they've turned debug mode off and it's still showing detailed errors.
Checking the current value at runtime
if (config('app.debug')) {
// debug mode is on
}
A safer pattern for staging environments
If a staging environment needs more detail than production but shouldn't be fully public, prefer a proper logging/error-tracking setup (Sentry, Flare, or just detailed log-level configuration) over enabling APP_DEBUG — that gives developers the detail they need without exposing it to every visitor who happens to trigger an error.