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.$APP_ENV.local
(don't commit this file to the repository) defines environment-specific overrides for your local machine;.env.$APP_ENV
(commit this file to the repository) and defines environment-specific defaults for all developers/machines;.env.local
(don't commit this file to the repository) overrides the main.env
config only for your local machine;.env
(commit this file to the repository) and defines the default values for the env vars used in the application.
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: https://twitter.com/storresi/status/1057242707914043392
Hey guys!
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: https://github.com/symfony/recipes/pull/466/files#diff-d611993c75871b5e812244b9a8cf54d4
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.
Cheers!
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 😉
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?
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!
Cheers!
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. https://docs.docker.com/compose/env-file/ 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)