Update on August 9, 2017: Grégoire Pineau mentioned on Slack to remove the incenteev/composer-parameter-handler composer package to avoid errors while using Composer. You are encouraged to do so.

Environment variables are increasingly popular to manage your application configuration. They are one of the main concepts of the twelve-factor app methodology. Their main advantages are that they can be changed between deploys without changing any code and that they don’t need to be checked into the code repository.

Since Symfony 3.2 there is full support for environment variables and in Symfony 3.3 the old SYMFONY__ variables are deprecated and will not be treated special anymore by Symfony in 4.0. The old variables behavior was simple, when the application container was built, the values of those environment variables were dumped into the compiled container. Therefore, if those variables changed during the application execution, the updated values were ignored.

Symfony released a new component named DotEnv in January 2017. In practice, the Dotenv component parses .env files to make environment variables stored in them accessible in your application via getenv(), $_ENV or $_SERVER.

We are going to replace the parameters.yml and parameters.dist.yml files in the Symfony Standard Edition with the new DotEnv component. The first thing you should do is open up a new terminal and type in the following command:

rm -f app/config/parameters*

Do not forget to remove the include of the parameter file in app/config/parameters.yml. Create a new file called .env.dist and add the following content:

APP_ENV=
APP_DEBUG=
APP_SECRET=
DOCTRINE_URL=

Also create a new file called .env and don’t forget to add .env to your .gitignore file. You do not want to commit your parameters into your version control:

APP_ENV="dev"
APP_DEBUG="1"
APP_SECRET="22bdd8c5ce986c6fe841a02badb8ffd42353b6f5"
DOCTRINE_URL="mysql://root@127.0.0.1:3306/symfony?charset=utf8mb4&serverVersion=5.7"

The .env file above is a example of a development environment. You should adjust the parameter values to match your current environment. You’ll need to adjust some values in the app/config/config.yml file. A example that matches the example above:

framework:
    secret: '%env(APP_SECRET)%'

doctrine:
    dbal:
        url: '%env(DOCTRINE_URL)%'

Now it’s time to edit some Symfony critical files to make use of the new component. First of all, we will replace the file bin/console with the content below:

#!/usr/bin/env php
<?php

use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Debug\Debug;
use Symfony\Component\Dotenv\Dotenv;

set_time_limit(0);

/** @var Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__ . '/../vendor/autoload.php';

if (!getenv('APP_ENV')) {
    (new Dotenv())->load(__DIR__ . '/../.env');
}

$input = new ArgvInput();
$env = $input->getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev');
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod';

if (getenv('APP_DEBUG')) {
    Debug::enable();
}

$kernel = new AppKernel(getenv('APP_ENV'), getenv('APP_DEBUG'));
$application = new Application($kernel);
$application->run($input);

Now we will have to create a new file in the web directory called index.php to use the new component:

<?php

use Symfony\Component\Debug\Debug;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\HttpFoundation\Request;

require __DIR__ . '/../vendor/autoload.php';

if (!getenv('APP_ENV')) {
    (new Dotenv())->load(__DIR__ . '/../.env');
}

if (getenv('APP_DEBUG')) {
    Debug::enable();
}

$kernel = new AppKernel(getenv('APP_ENV'), getenv('APP_DEBUG'));
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

Now you can delete both app.php and app_dev.php. To conclude, you are now using the new Symfony DotEnv component and are not longer using the old parameter files. You should make sure that your deployment application keeps the production .env the same on every deployment (shared between deployments) and for other environments like staging or testing.