New in Symfony 4.2: Define env vars per environment

Contributed by
Kévin Dunglas
in #28533.

Since the introduction of the DotEnv component in Symfony 3.3, we've been working hard to improve the experience of using env vars to configure Symfony apps. In Symfony 4.2, we've added a new loadForEnv() method to allow you define different env vars per environment.

Instead of creating a single .env file at your project's root dir, you can now create one or more env var files. The values for the env var are looked for in the following order:

  • .env + environment name + .local (, .env.test.local). These are the environment-specific settings overridden locally on your machine.
  • .env.local. Used for overriding values on your local machine. This file is loaded for all environments except test.
  • .env + environment name (, .env.test). These are the files that define environment-specific settings. Useful for example to override settings like the database connection for tests.
  • .env. Same file as used by current Symfony apps.

We're working on a Symfony Flex recipe to bring this new feature into the full Symfony framework (see symfony/recipes #466). There's no need to change anything in your existing applications if you don't want to, but new projects will get the latest recipes versions, with the following changes:

  • .env renamed as .env.local (and "gitignored").
  • .env.dist renamed as .env (and committed to the shared repository).


This seems very confusing on first glance. Are there any other projects using a similar setup? Using `.env` and `.env.dist` is fairly common practise as far as I've seen.

What is the use case for this that isn't already solved using parameters?
This seems strange to me too. It changes a normal and widely used common practice, just to avoid duplication?

Also, I agree with my friend here:
Hey guys!

> Are there any other projects using a similar setup?

Great questions / comments. Actually this new setup was done purposely to follow a standard used by others like Create React App and Rails. So, we're becoming *more* standardized.

But, that's not the *real* reason I'm excited about this. The *real* reason is that it enables us to drastically improve env vars in the test environment via this recipes PR:

Currently you need to duplicate your env vars (all of them) in phpunit.xml.dist... even if only a few need to be different in the test environment. In the above recipe PR, the proposal is to introduce a new src/bootstrap.php file that everything uses (phpunit, public/index.php & bin/console) that will load environment variables in a consistent way. By combining that with the ability to have a .env.test file, you can easily tweak your test environment settings. This is big thing that I think needed to be improved.

Other than that recipe PR, for most people, this change won't mean much. As the post mentioned, .env.dist will become .env (and be committed) and .env will become .env.local (and not be committed). But this is just a naming change.

Thanks Ryan. I've got to admit, I still don't understand how the use case of environment-specific env files isn't already covered by parameters, but perhaps I'll need to see an example project before I can get my head around it.

Will the best practices docs be updated to include this?
I'm not really fond of the fact that .env is becoming the new .env.dist file, because some other pieces (i'm thinking docker-compose here) use .env variables as well, and i don't feel like using placeholders that formerly were in .env.dist instead of what should actually be in my .env 😉
> Jaik: I've got to admit, I still don't understand how the use case of environment-specific env files isn't already covered by parameters

Great question/point actually! We just had that conversation on the recipe pull request. You CAN actually set environment variables on a per-environment basis by using the special parameters syntax. But, at the very least, it's way less user-friendly than having a .env.dist file for overrides (which will be installed for you when you install phpunit-bridge).
Thanks! Awesome change :-)
It will make our life easier!
@Ryan Are you suggesting moving away from using parameters for per-Symfony-environment config, and using environment variables instead? To me things like whether to use a live or test payment provider belong in parameters, whereas things like database credentials are environment variables. Does that distinction between the version of the app you're deploying (eg. prod, sandbox) and the hosting environment you're deploying it to still remain?
> Jaik: Are you suggesting moving away from using parameters for per-Symfony-environment config, and using environment variables instead?

Ah, no - I didn't mean to make it sound like this exactly. Most of the time, it still makes more sense to override environment config in a config file - e.g. services_test.yaml or config/packages/test/*. Or, like how we have 2 different monolog.yaml files for dev vs prod environment. You want these changes committed - they are code. But, for values that are already stored in .env (e.g. DATABASE_DSN), it's just a lot simpler to be able to have a `.env.test` vs knowing to create a config/packages/test/doctrine.yaml file that has the config you need to re-set the database_dsn. That's my main motivation for liking this change.

Good questions! It's helpful to have to me to these discussions!

Welcomed update… no more DATABASE_URL_TEST, MAILER_URL_TEST vars :)
Thanks Ryan.
This is confusing to me...
So we have environments for environment variables
I agree with Asmir. The whole reason for having a .dist file is so it can be copied to different environments with different values.

The only reason for rolling this out is so that unittests can be configured easier? Just put the ENV values you need in the phpunit.xml!
Great change, handling params for test env in phpunit.xml.dist and phpunit.xml was not intuitive.
I wanted to like this change. But with further investigation...

I have a setup script that helps to get the project up and running quickly. The setup script sources the .env file or loads real env vars if that file doesn't exist. I'm still not sure how to fix this. The only way I can think of, is to implement the same conditional logic in my setup script that DotEnv uses, to look for and load any relevant "override" files.

Docker Compose looks for .env files by default.
It was nice that I didn't have to do anything to make docker properly host my application in development.

IMO this is a significant change that can be obviated with a .env.test file and having w/e test runner source that file and then let Symfony fill in the gaps from the .env file. No changes necessary. (CMIIW)

Comments are closed.

To ensure that comments stay relevant, they are closed for old posts.