Hi, you can know your running environment with :
app()->environment()
So you get the APP_ENV value : local, testing ....
But you must have only one .env file. But also look at this discussion.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Hi, my question is related with the .env files.
Is possible to have multiple .env files within the same application?
How to know when I'm using a .env or .env.testing file?
I'd like to use a .env file generally, but for testing questions use .env.testing.
I tried using Dotenv class and $app->loadEnvironmentFrom() but it doesn't work or I'm using in an incorrect way.
I think an environments lesson would be very useful.
Thanks in advanced.
Hi, you can know your running environment with :
app()->environment()
So you get the APP_ENV value : local, testing ....
But you must have only one .env file. But also look at this discussion.
Thanks @bestmomo, but then I'm missing something about testing environments.
If not possible to have several .env files? Imagine you are working with your general database and you need to simulate some behaviour using a testing database, do you need to change your .env params to use a testing database? is not possible to use both of the databases with your project?
In principle you should change the .env file for each situation because environment is loaded when app start :
/**
* The environment file to load during bootstrapping.
*
* @var string
*/
protected $environmentFile = '.env';
It's possible to change it with :
/**
* Set the environment file to be loaded during bootstrapping.
*
* @param string $file
* @return $this
*/
public function loadEnvironmentFrom($file)
{
$this->environmentFile = $file;
return $this;
}
But not sure to where to put it for test, I have to look forward with some testing.
The main principle behind the .env files is that you have one per environment. The .env file you have in your production environment (Linode/DigitalOcean/AWS/etc) has values specific to configuration for your production environment and is different to the .env file you have in your local (Homestead) or development environments.
If you need some specific values for testing, you can configure/override them in your test environment using syntax in phpunit.xml.
I've just been looking at this stuff this morning. still confused
I kinda miss the L4 local {whatever} config dir, and for me putting different stuff into files with the same name seems a retrograde step. I know its in .gitignore but I get things wrong all the time and I just see a blow up waiting to happen with this.
Is anybody able to comment on this clip from the phpdotenv docs:
phpdotenv is made for development environments, and generally should not be used in production. In production, the actual environment variables should be set so that there is no overhead of loading the
.envfile on each request.
In the production environment, you would likely set the environment variables based on the operating system you're using.
That could be within nginx / apache configuration, or for the user the web server is running as (less likely). The .env file is a quick workaround that means you can easily add / change / remove environment variables whilst developing, without having to restart nginx / apache each time.
yea I understand the technicalities of it. But practically it doesnt make a lot of intuitive sense to me.
Doing that way pushes my laravel config stuff outside my laravel app. And some people may not have access to, or feel able to mess with httpd config files.
And I've seen no mention of that aspect of using .env files anywhere yet. There's a vid here which doesnt cover it. L5 Docs dont cover it. And generally there seems to be confused people (me anyway) wandering about looking where to put their local/testing/production configs in L5
I'm just old fashioned and I totally fear change thats all!
I'm confused as well.
I'd like to know this as well. While it was annoying to mix the .env files with folders for config, it seems needlessly complex to put every variable configuration option in an env file. I hope there's a more elegant solution in the works for this, otherwise I suspect someone is going to develop a package to mimic L4's method.
Moving away from the .env files helps minimise the risk of something like this happening.
Any proper (Laravel) hosting solution allows you to set environment variables through their management tools, and Forge definitely does it for you. Sure, the .env files were ignored before, but accidents happen. Maybe you called your file env.php instead of .env.php and pushed it up to GitHub.
Putting every variable into a config is a bit of extra effort (that you are doing once per environment), but in my opinion the benefit outweighs the effort involved. At my last job, we had a configuration file that was environment-specific, which had dozens of parameters in it. It was a bigger pain to move everything to the config and update references than it was to add a new parameter when we needed it.
I'm sure somebody will find a way around using single config files with L5, I just think doing so would be a disservice.
@Deringer: but how is setting configs in a different file then .env making any difference regarding such accidents? If you push any config file with sensitive info to a Github repo it can cause the same trouble?
So using .env file for config settings is discouraged now? What is the default/best practice now?
@Mattiman docs show that using .env file is the recommended method. You use a separate .env file per environment. (Altho phpdotenv docs state it shouldnt be used in production. I have no idea how it performs, no doubt somebody has tested it)
But heres a quote from upgrade docs and for me this is the hard bit:
Laravel 5.0 no longer uses app/config/{environmentName}/ directories to provide specific configuration files for a given environment.
my L4 apps have config/local config/testing config/staging etc dirs, and each of those dirs has specific files that keeps stuff nicely compartmentalized - for me anyway.
But thats gone in L5 and instead we switch all that env specific disparate stuff into 1 file per environment, and its always called the same thing (.env) and its always in the same place.
as you say:
If you push any config file with sensitive info to a Github repo it can cause the same trouble
I will mess it up for sure ;-)
Just don't delete the gitignore files and push to private repos first.
@thepsion5 I'm with you, I think that the .env is going to get so ugly with all of the potential variables in it & the config files are going to get so polluted with env() method. I did the PR...
https://github.com/laravel/framework/pull/6916/files#r22465914
But it was shot down. I too hope that they put out something better.
Laravel has never quite handled configuration correctly, unfortunately (at least, not without making the developer write a lot of needless boilerplate in team-based environments).
I've used Laravel for doing CMS-like work where all developers contribute content to a shared staging database, but can switch to a local database for testing and development. It's actually a pain in the ass setting up this config switching in Laravel 4, and it appears it's even MORE of a pain in the ass now that named environments and multi-environment support is not there.
Looks like I'm going to have to resort to pulling in a content migrations tool and doing content entry through migrations :S
Not a fan....
@Mattiman, the .env files are a workaround to setting environment variables.
If you look at the dotenv readme
Shim to load environment variables from
.envintoENVin development.Storing configuration in the environment is one of the tenets of a twelve-factor app. Anything that is likely to change between deployment environments–such as resource handles for databases or credentials for external services–should be extracted from the code into environment variables.
But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. dotenv loads variables from a
.envfile intoENVwhen the environment is bootstrapped.
Storing configuration in the app/config/{environment}/{file}.php is messy - the values in the configuration files ought to read from the environment (using getenv("PARAM")) - not be hardcoded into the files themselves. You're having to ignore your {environment} directories to keep per-developer configuration out of version control. My local configuration will be different to another developer in my team's configuration (his own homestead or WAMP/MAMP/LAMP environment). You can't (shouldn't) commit your local configuration files into version control, because it's different to the next developer's configuration. In Laravel 4, each developer needs to add their own configuration directory structure - they shouldn't have to.
What the L5 method actually does is simplify configuration. You only ever have one set of configuration files (under config) that are under version control in your application and you define the configuration values in the environment, whether that be a .env file or in apache, nginx, bash, or otherwise.
In your production environment, the .env file shouldn't even exist; it only simulates the presence of data defined in the environment. It's for this reason the file itself is ignored and not shared in VCS. Any value that changes per environment - whether that be local to production, or multiple local (developer) setups - should be read out of the environment.
I'm not taking a stab at anybody, if you're happy with the current setup, that's fine; I'm not saying you're wrong. If I'm not being clear, please let me know and I'll try and clarify for you.
@deringer: thanks for your explanation. It's getting clearer now. I wasn't specifically disagreeing with some method, it was just confusing. I've never used real environment variables before, so didn't understand what was meant. Not sure if I can even set them with any of the web hosts I work with, probably not (almost all regular shared hosting packages).
So, if I understand correctly now: - the default for production (on the live server) should be setting the configs in environment variables on the server - if that's not possible or to override them in a different environment (local dev or testing) you create the .env file with the configs
So, if I develop locally (on a Homestead box or Mamp), I will have to create 2 .env files, and each time I want to switch between testing (using a testing database for example), I put the test .env in the root dir, if I want to switch to development I put the development .env there. Right? A bit of a hassle, but I guess I can live with that.
@Mattiman I think possibly the solution will be to specify env vars for testing in the /phpunit.xml file, and use the .env file for your local config.
I'm not sure what the precedence is though, whether the .env will override - I'm currently looking into this.
What I haven't quite figured out is a nice way to separate more complex config, like for example my default connection on prod is mysql but on testing is sqlite.
I used to specify this default in a config/testing/database.php file, and don't really want to turn that into an environment variable config parameter...
@spronky you'd set the default database driver in your environment, then the relevant environments-specific configuration as needed (i.e. sqlite driver with db path in testing, mysql with credentials in production).
@Mattiman if your shared hosting supports .htaccess (I'm assuming it does if you're running Laravel apps on it), you can set the environment variables there, assuming the server also has mod_env configured.
If it's not possible to set proper environment variables, then you can revert back to using the .env file on your production host still.
When developing locally, you can set specific environment variables in your test environment within the phpunit.xml file - this is the way that APP_ENV is set to testing out of the box. Bear in mind this file is checked into your VCS, so don't store any passwords or keys/tokens in there - anything sensitive should still be in a .env file - which you can load as part of your test setup.
@spronkey and @deringer: didn't know about the phpunit.xml file.
@deringer: I have access to htaccess. So that's an option as well.
But now that I know about all the options, I still have questions about the best and easiest set up. - I develop locally in Homestead using a mysql db. - In L4 when running Unit tests, I could easily set it up so the Unit tests use a different database. - code is pushed to Github - live code is transferred from local to the live server with FTP
So in L5 is it still possible to have one code base and let the Unit tests use a different database (maybe in memory sqlite)? Or should I switch the .env files each time I want to go from dev to testing and back?
Is it possible to specify configuration values that are an array ? For example, if I have something like:
'hosts' => get_env('APP_HOSTS', ['localhost'] )
@Mattiman - you can specify the database driver in the same way that the cache and session drivers are set to array in phpunit.xml, then update database.php to something along the lines of:
// ...
'default' => getenv('DB_DRIVER', 'mysql'),
// ...
That way if DB_DRIVER is set in your environment, Laravel will use that otherwise it will default to mysql. You can modify the database path in database.php or you can specify that in your environment, too - it's up to you.
@thepsion5 - I don't believe so. Environment configuration appears (based on the test fixtures and the documentation) to support only single values. You could get creative and store a JSON-encoded string in an environment variable, though.
@deringer: thanks for the advice. It's clear now.
What is not clear, is how I need to specify the phpunit.xml if I want to use a sqlite in memory db. In laravel 4 it used to be:
//app/config/testing/database.php
return array(
'default' => 'sqlite',
'connections' => array(
'sqlite' => array(
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
),
),
);
But how do I specify that in the xml?
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="bootstrap/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false">
<testsuites>
<testsuite name="Application Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="DB_HOST" value="localhost"/>
<env name="DB_DATABASE" value="myprojectdb"/>
<env name="DB_USERNAME" value="homestead"/>
<env name="DB_PASSWORD" value="secret"/>
</php>
</phpunit>
I've not tested this @Mattiman, but it should get you in the right direction:
// config/database.php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => env('DB_DRIVER', 'mysql'),
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => env('DB_SQLITE_PATH', storage_path().'/database.sqlite'),
'prefix' => '',
],
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
],
];
// phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit ...>
...
<php>
<env name="APP_ENV" value="testing" />
<env name="CACHE_DRIVER" value="array" />
<env name="SESSION_DRIVER" value="array" />
<env name="DB_DRIVER" value="sqlite" />
</php>
</phpunit>
What this is doing is telling Laravel to use DB_DRIVER as the default database connection and when not set, to use mysql. You only need to specify the DB_DRIVER environment variable within your phpunit.xml - in this instance to sqlite.
When your tests run, your app environment will be set to testing, cache and session drivers to array, and database driver to sqlite.
In order to specify that you want to use an in-memory database, you would just set your DB_SQLITE_PATH to :memory: in the same way you would have entered that value within your Laravel 4 app/config/testing/database.php file.
Let me know how you go.
I suspect someone is going to develop a package to mimic L4's method
looks like @crynobone already did it, I just came across this:
https://github.com/orchestral/config
I had a quick look and it seems to work good with a bare L5 install. It allows nested config dir based on env, and config items can be arrays. Hopefully it resolves some mess for me anyway.
l.
Hi Deringer, thanks for the help. I tried your code. So now my phpunit.xml looks like:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="bootstrap/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false">
<testsuites>
<testsuite name="Application Test Suite">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="DB_DRIVER" value="sqlite" />
</php>
</phpunit>
And my config/database.php looks like:
<?php
return [
'fetch' => PDO::FETCH_CLASS,
'default' => env('DB_DRIVER', 'mysql'), //'mysql',
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
But now my unit tests trigger lots of errors. Thinking it has something to do with the seeding of some tables missing in the sqlite memory db, I tried adding Artisan::call('db:seed'); to my DbTestCase file:
class DbTestCase extends TestCase {
/**
* Setup the DB before each test.
*/
public function setUp()
{
parent::setUp();
// This should only do work for Sqlite DBs in memory.
Artisan::call('migrate');
Artisan::call('db:seed');
// We'll run all tests through a transaction,
// and then rollback afterward.
DB::beginTransaction();
}
/**
* Rollback transactions after each test.
*/
public function tearDown()
{
DB::rollback();
}
}
But then ALL my tests fail. And the tests run very slow. The idea of using a memory sqlite was that it was faster.
So not sure what is happening here.
Can you verify that the environment variables are definitely set correctly?
Have you tested that the migrate and db:seed artisan commands work for the in-memory DB outside of the unit tests?
What errors are you getting?
"Can you verify that the environment variables are definitely set correctly?" How would I do that? What I do know is that if I add:
<env name="DB_DRIVER" value="sqlite" />
I get the Failed unit tests. If I remove that line (so it runs on the mysql db), the Unit tests return green.
"Have you tested that the migrate and db:seed artisan commands work for the in-memory DB outside of the unit tests?" No, I haven't tested that yet. Never worked with sqlite or sqlite in memory before. Will try.
"What errors are you getting?" The errors are just the failed unit tests errors:
FAILURES!
Tests: 29, Assertions: 38, Errors: 11.
You can dd(env('DB_DRIVER')) inside your test and see that it returns 'sqlite'
Please or to participate in this conversation.