Laravel debug mode: enabling, disabling and the config cache

Laravel debug mode: enabling, disabling and the config cache
Quick answer

Debug mode is controlled by APP_DEBUG in the .env file: true locally, false in production, always. Check the real state with php artisan about --only=environment. If the change has no effect, the configuration is cached: run php artisan config:clear.

Debug mode decides what a visitor sees when your application crashes: the full stack trace with source code and environment variables, or a neutral error page. It is a one-line setting, and also one of the most common data leaks in production.

Part of the Web development reading path. Checked on Laravel 13.30.1 with PHP 8.4.25.

Turning it on and off

The setting lives in the .env file at the root of the project, and nowhere else:

.env
APP_ENV=local
APP_DEBUG=true

To turn it off, set the value to false:

.env
APP_ENV=production
APP_DEBUG=false

Check the effective state without writing a single line of code:

bash
php artisan about --only=environment
code
  Environment ........................................................ local
  Debug Mode ...................................................... ENABLED

That is the only check that counts: it shows the value the application really uses, cache included.

The trap: cached configuration

You set APP_DEBUG=false, you reload, and the stack traces are still there. It is almost always the configuration cache.

Once php artisan config:cache has run, Laravel writes every resolved value into bootstrap/cache/config.php and stops reading the .env file altogether. The behaviour was measured:

Step config('app.debug') env('APP_DEBUG')
APP_DEBUG=true, no cache true true
after config:cache, then switched to false in .env true NULL
after config:clear false false

Two lessons. The first: after any change to .env on a server where the configuration is cached, you have to rebuild it.

bash
php artisan config:clear
# or, in production, rebuild the cache straight away
php artisan config:cache
env() returns NULL when the configuration is cached

This is the least understood consequence, and it goes well beyond debugging. A call to env('MA_CLE') anywhere outside a config/ file returns null as soon as config:cache has run. The rule is strict: env() inside config/ only, and config('fichier.cle') everywhere else.

What config/app.php contains

The configuration key does nothing more than read the environment variable, with false as the fallback:

config/app.php
'debug' => (bool) env('APP_DEBUG', false),

Leave that line alone. It is written so the default behaviour is the safe one: if APP_DEBUG is missing from .env, debug mode stays off. Checked by removing the variable, config('app.debug') does return false.

Hard-coding the value in config/app.php has two drawbacks: the file is under version control, so the setting ships to every environment, and the .env file becomes misleading.

The accepted values follow Laravel’s conversion rules, measured line by line:

In .env config('app.debug')
APP_DEBUG=true or (true) or 1 true
APP_DEBUG=false or 0 false
APP_DEBUG=yes true
variable missing false

yes evaluates to true because the string is not recognised as a boolean and ends up being cast. That is a good reason to stick to true and false.

Why false in production is not negotiable

With APP_DEBUG=true, the error page shows the call stack, snippets of source code and the contents of the loaded environment variables. A visitor who triggers an error can therefore read your database credentials, your API keys and the APP_KEY that encrypts your sessions.

No hunting is needed: one URL that throws an exception is enough. That is how Laravel applications end up compromised without any particular flaw in the application itself.

The right configuration for a production server, like the one built in installing Laravel on Debian, fits in three lines:

.env
APP_ENV=production
APP_DEBUG=false
APP_URL=https://exemple.com

Then, once deployed:

bash
php artisan config:cache
php artisan about --only=environment   # check: Debug Mode must show OFF

The same reasoning applies to public forms, which need protecting against automated submissions before you open them to the world.

Errors are still there to read, but in the logs rather than in the browser:

bash
tail -f storage/logs/laravel.log

That path is built with storage_path(), covered in the application paths.

Common errors

The configuration cache ignores .env After config:cache, Laravel no longer reads the .env file. Any change calls for config:clear or a cache rebuild.
env() outside config/ As soon as the configuration is cached, env() returns NULL everywhere else. Use config('fichier.cle').
Editing config/app.php instead of .env The file is under version control: the setting ships to every environment and the .env file becomes misleading.
APP_DEBUG=yes evaluates to true Any string not recognised as a boolean is cast to true. Stick to true and false.
APP_DEBUG=true in production The error page exposes the stack trace, the source code and the environment variables, including the database credentials and the APP_KEY.

ConfigurationLaravelPHP

Damien Flandrin Web developer since 2010, creator of Gekkode and Email Impact. Every article is tested on a real project before publication. Contact
Newsletter

New tests, tutorials and projects, by e-mail.

Reproducible tests, versioned code, dated results. Never any spam.