Environments
dev, test and prod are named configuration sets chosen by APP_ENV; when@prod keeps each difference visible in one file.
when@prod: in YAML / APP_ENV=prod php bin/console <command>An environment is a named set of configuration applied to one codebase. The same classes run in all of them; only the options differ. The name comes from the APP_ENV variable and is available in configuration as %kernel.environment%.
The three that ship
dev shows detailed error pages, enables the profiler, and rebuilds the cached container when a file changes. test is used by the test suite and usually swaps in test doubles and a separate database. prod compiles the container once, logs errors instead of displaying them, and does not watch for file changes.
APP_DEBUG is a separate switch. It controls error detail and cache rebuilding, and it is not the same thing as the environment name, even though dev defaults to debug on and prod to debug off.
Four places a difference can live
A file in config/packages/<env>/; a when@<env> block inside a normal configuration file; config/services_<env>.yaml; and the per-environment flags in config/bundles.php. Prefer when@prod: the override sits next to the default it overrides, so the difference is one readable diff instead of a file you forget exists.
What trips people up
Every difference between environments is behaviour that only production can expose. Keep the list short, write it down, and run at least one check against APP_ENV=prod before deploying. A command run without APP_ENV uses the value in .env, so clearing the cache locally does not clear the production one.
Example
// public/index.php
declare(strict_types=1);
use App\Kernel;
// autoload_runtime.php reads the .env files and the real environment,
// then calls the closure below with the result in $context
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
// this is the only place the environment name and debug flag are chosen:
// APP_ENV picks which config files load, APP_DEBUG is a separate switch
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};
// A request to GET / with APP_ENV=dev and APP_DEBUG=1 returns 200 with the
// profiler toolbar at the foot of the page. The same request with APP_ENV=prod
// returns the same page without the toolbar, and an uncaught error returns a
// plain 500 page instead of the stack trace.
When to use it
- Send mail through a local catcher in dev and a real provider in prod, with the difference on one screen.
- Enable the profiler and the maker tools in dev without shipping them to production.
- Prove before a deploy that production will read the logging and cache settings you expect.
More examples
One difference, visible in one file
The default and the production override sit in the same file, so a reviewer sees both at once. This is the readable form of putting a second monolog.yaml in config/packages/prod/, which does the same thing but hides the difference in another directory.
# config/packages/monolog.yaml
monolog:
handlers:
main:
type: stream
path: '%kernel.logs_dir%/%kernel.environment%.log'
level: debug
when@prod:
monolog:
handlers:
# buffer everything, and write the buffer only when an error happens
main:
type: fingers_crossed
action_level: error
handler: nested
nested:
type: stream
path: php://stderr
level: debugAn override in its own directory
The directory form, which recipes still use for tools that exist in one environment only. Reach for it when the override is long enough that a when@ block would bury the default, and accept that you have to remember the file is there.
# config/packages/dev/web_profiler.yaml
# everything in config/packages/dev/ loads only when APP_ENV=dev
web_profiler:
toolbar: true
framework:
profiler:
collect: trueRunning a command in another environment
The --env option and the APP_ENV variable are interchangeable on every console command. Running a configuration dump under prod is the cheapest way to catch a value you only set in a dev file.
# uses APP_ENV from .env / .env.local
$ php bin/console cache:clear
# the same command against prod configuration, two equivalent forms
$ php bin/console cache:clear --env=prod
$ APP_ENV=prod php bin/console cache:clear
# check what prod will actually see before you deploy
$ APP_ENV=prod php bin/console debug:config framework
$ APP_ENV=prod php bin/console debug:container --env-vars
Discussion