Improvements to the Handling of .env Files for all Symfony Versions

When Symfony 4.0 was released, the .env file was introduced as a way to set environment variables. The core of the system has not changed. But, thanks to recent updates to some core Symfony recipes, .env loading has some new features that can be enjoyed on any Symfony Flex project!

If you have an existing Symfony app (started before today), your app does not require any changes to keep working. But, if/when you are ready to take advantage of these improvements, you will need to make a few small updates.

What Changed Exactly?

But first, what changed? On a high-level, not much. Here's a summary of the most important changes:

  • A) The .env.dist file no longer exists. Its contents should be moved to your .env file (see the next point).
  • B) The .env file is now committed to your repository. It was previously ignored via the .gitignore file (the updated recipe does not ignore this file). Because this file is committed, it should contain non-sensitive, default values. Basically, the .env.dist file was moved to .env.
  • C) A .env.local file can now be created to override environment variables for your machine. This file is ignored in the new .gitignore.
  • D) When testing, your .env file is now read, making it consistent with all other environments. You can also create a .env.test file for test-environment overrides.

Point (D) is one of the main motivations behind these changes: it makes setting and overriding environment variables for your test environment a delight.

These improvements can be used in any Symfony Flex project (Symfony 3.4 or higher). Changes to the recipes (see below) make it possible to take advantage of the Symfony 4.2 feature - Define env vars per environment - in lower versions.

To take advantage of these, you will need to modify a few files in your existing app.

Updating My Application

Updating your existing application is optional, but just requires modifying a few files. To update, see: DotEnv: Update my Application in the Symfony Docs.

Bonus: --env & --no-debug Console Deprecations Removed

The --env and --no-debug were recently deprecated. However, based on community feedback and work on these new .env features, the deprecation has been reverted: the --env and --no-debug options will continue to work! And, the proper .env files will be loaded. For example, want to create the schema in your test environment using a customized DATABASE_URL in your .env.test file? That will work just like you expect:

1
$ php bin/console doctrine:schema:create --env=test

Have any questions? Let us know!

❤️ The Symfony Community

Comments

I'm still a bit lost as to the point of these changes, but it seems enough people understand it, so I'll get stuck in as part of upgrading to 4.2! In this example, should `.env.test` be committed? Is there a corresponding `.env.test.local` or `.env.local.test`? What is the order of precedence?
This isn't an improvement I could apply to my project, as we also use docker-compose and a `.env` file to automatically load environment variables handled as secrets that cannot be committed to the repo.
> Jaik Dean: I'm still a bit lost as to the point of these changes

There was one big issue that needed to be fixed: the .env file was not loaded in the test environment, which meant that you needed to duplicate all of your env vars in phpunit.xml.dist. That was basically a "bug" that needed to be fixed.

The fix for that was to add the ability for Symfony to load .env.{env} files (e.g. .env.test)... and that's all we really needed. But, several other (less important) features were also added, like the ability to have .env.test.local, and also the decision to move away from the .env.dist file in favor of committing the .env file. That last part was really unrelated to fixing the above "bug", and I think its the part the will be the most difficult - we need to re-teach the purpose of the .env file, and (while it's really nice) this one part doesn't give us any new concrete feature.

To summarize:

1) .env will be committed
2) .env.local will not be committed (local overrides)
3) .env.test will be committed

And you probably won't need to create any other files. You CAN create other files (e.g. .env.test.local), but I don't think there will be common cases for this. Any files matching `.env.*.local` are ignored in .gitignore.

Let me know if you have other questions!
It was I was already doing! Happy to see it in by default.
Will DotEnv check if we're overriding locally the existing (correct) env variable? Will these files be synchronized somehow?
> Piotr Karszny: Will DotEnv check if we're overriding locally the existing (correct) env variable? Will these files be synchronized somehow

By "existing (correct) env variables" are you referring to "real" env vars that you may have set? If so, that behavior hasn't changed: the DotEnv component (which loads all these .env files) will never override a "real" environment variable that you have set. So, for example, if you are in the "test" environment, Symfony will load .env and .env.test. But, if any of the env vars set in those files already exists as a true environment variable, the value in the file will NOT override the real environment variable value :).

Cheers!
@ryan ok, thank you! :)
Finally! Testing environment was my main issue when I started using .env files and had to do some nasty hacks to solve all the issues.

It's good to see the deprecation being reverted too.

What do I need to update to use the new .env.test? Just symfony/flex? Is it in stable already?
Really good news for the testing environment (which was a real problem when it comes to env variables).

Small question about the production environment, if we can't use env variables (maybe due to a lack of SSH, etc), can a `.env.prod` file can be defined ?
> Ismael Ambrosi : "This isn't an improvement I could apply to my project, as we also use docker-compose and a `.env` file to automatically load environment variables handled as secrets that cannot be committed to the repo."

As Docker use the .env file, I think you can continue to keep it out of the Git index and keep a .env.dist which is the structure for the .env file, plus, as Symfony use a .env.local file, the content of the .env file isn't really "important" (mainly because you can use both .env.test and .env.local in order to overload the env variables, finally, the .env.local can be used as the only source of truth (without using a .env file for Symfony), this way, you can keep your secrets in the .env file without breaking all your infrastructure).
> Jáchym Toušek: What do I need to update to use the new .env.test? Just symfony/flex? Is it in stable already?

Check out the details for how to update here: https://symfony.com/doc/current/configuration/dot-env-changes.html#updating-my-application

Basically, you just need to modify a few files to match the changes that were made in the recipes :)

> Loulier Guillaume : Small question about the production environment, if we can't use env variables (maybe due to a lack of SSH, etc), can a `.env.prod` file can be defined ?

Yep! Except, instead of .env.prod, just create a .env.local on your production machine. .env.prod would also work - but it doesn't make as much sense (e.g. if you, for some reason wanted to execute a console command in the "dev" environment on production, the .env.local would STILL be read, but a .env.prod would not).

In general, if setting real env vars works well with your deployment environment, use those. If they do not, there is no significant disadvantage to creating a .env.local file.
@Ryan Weaver: Thanks for the feedback, I'm gonna check this in my old projects that I move to Sf 4 :)
> There was one big issue that needed to be fixed: the .env file was not loaded in the test environment, which meant that you needed to duplicate all of your env vars in phpunit.xml.dist. That was basically a "bug" that needed to be fixed.

We utilze bootstrap file injecting dist by default for testing purposes. For e2e tests we run docker-compose with env_file: [.env.dist] so we have full control of what's happening.

New changes are confusing and break current best-practices about .env files
I just tried it and it works well. I now have 3 files .env, .env.local and .env.prod.

Thanks
This post does confuse me a little bit.

Do I need Dotenv in prod? I thought it was for dev only.

When I am in prod and calling a command should I source a file with envvars or using .env.local? What approach is more best practice?
> André Baldeweg : "This post does confuse me a little bit.

Do I need Dotenv in prod? I thought it was for dev only.

When I am in prod and calling a command should I source a file with envvars or using .env.local? What approach is more best practice?"

In fact, in production (except if you don't have full access to the terminal), you should use env variables (using vhosts or server env), the .env.local is really linked to the development case.
A little repeat answer, but just to make sure it's really clear:

> @André Baldeweg Do I need Dotenv in prod? I thought it was for dev only.

You do not need Dotenv in prod. You *can* use it if you want to, but it's up to you. If Symfony sees a real APP_ENV environment variable set to "prod", it will not load your .env files.


> When I am in prod and calling a command should I source a file with envvars or using .env.local? What approach is more best practice?

When you're on prod, you will either choose to:
A) Create real environment variables
or
B) Create a .env.local file with your production-environment env var values

You can choose either setup - whatever works best for you. When you run a command, you don't need to do anything: if you're using real env vars, those will naturally be used. And if you've chosen a .env.local setup (i.e. not setting real environment variables), that file will be loaded like normal. There's nothing special about running commands.

Cheers!
Thanks Loulier Guillaume and Ryan Weaver for making it clear!
Some strange change. It's not much use, but it's confusing.
I have made the changes as advised in https://symfony.com/doc/current/configuration/dot-env-changes.html#updating-my-application

I have
symfony/dotenv v4.1.4
symfony/framework-bundle v4.1.9

I have

.env
.env.local
.env.test

If I try and run this command

APP_ENV=dev php bin/console doctrine:database:create -n

It does not load the .env.local

I also tried

APP_ENV=local php bin/console doctrine:database:create -n

Also the .env.test is not used if I run

APP_ENV=test php bin/console doctrine:database:create -n

However, the following DO clear the caches for the correct environment

APP_ENV=dev bin/console cache:clear
APP_ENV=test bin/console cache:clear

I have tried restarting Apache
Login with SymfonyConnect to post a comment