Skip to content
Advertisement

Which Symfony environment variable is available in which file (.env, .env.local, etc.)?

I have just started a new Symfony 5 project (only worked on Symfony 3 before) and I am having a hard time to understand how values in .env and .env.local work together.

The Symfony docs say, that values in .env.local will override values from .env:

If you need to override an environment value (e.g. to a different value on your local machine), you can do that in a .env.local file:

All machines I am working on use the same basic setup (same DB server, etc.) but some values are different (DB name, password, etc.). Thus I wanted to put the common configuration in .env and the device specific values in .env.local:

# .env
...
DB_SERVER="localhost"
DB_VERSION="10.4"

DB_USER=${DB_DBNAME}

DATABASE_URL="mysql://${DB_USER}:${DB_PASS}@${DB_SERVER}/${DB_DBNAME}?serverVersion=${DB_VERSION}"
# .env.local
DB_DBNAME="someDB"
DB_PASS="secretPW"

When using this setup I get an error and php bin/console debug:container --env-vars shows DATABASE_URL "mysql://:@localhost/?serverVersion=10.4". Obviously DATABASE_URL is build ignoring the values from .env.local.

I can easily solve this by moving DATABASE_URL="mysql://... to .env.local but is this the intended way of using .env and .env.local?

I thought values of these files are merged where .env.local values override .env values. Is this not the case? Or did I make some error?

Advertisement

Answer

Which Symfony environment variable is available in which file (.env, .env.local, etc.)?

.env is loaded before .env.local, and each file is processed independently of each other.

For interpolation purposes, only the environment variables defined in the same file, or in in a file processed earlier, are available during .env file processing.

While environment variables defined in more specific env files do trump those defined in more general ones, in your example when DB_DBNAME and DB_PASS are overwritten/defined too late to be of use, since DATABASE_URL (which depends on those) is defined earlier and not redefined in the .env.local file .


But, you can accomplish what you want to do, you just have to do it a different way.

First, create your DATABASE_URL environment variable with parameter placeholders, like this:

DATABASE_URL="mysql://%DB_USER%:%DB_PASS%@%DB_SERVER%/%DB_DBNAME%?serverVersion=%DB_VERSION%"

Then, in your services.yaml file, define the container parameters for all these values:

# services.yaml
parameters:
    DB_DBNAME: "%env(DB_DBNAME)%"
    DB_USER: "%env(DB_USER)%"
    DB_PASS: "%env(DB_PASS)%"
    DB_SERVER: "%env(DB_SERVER)%"
    DB_VERSION: "%env(DB_VERSION)%"
    
# rest of your services.yaml file follows

It’s important that your doctrine configuration reads like this (which is the default), including the resolve bit:

# doctrine.yaml
doctrine:
    dbal:
        url: '%env(resolve:DATABASE_URL)%'

With this you’d get your desired results.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement