Laravel 5.0 - Environment Detection & Environment Variables

Posted on October 16, 2014 | By Matt Stauffer


Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

If you've followed my blog for a while, you've probably seen me struggle with Laravel's environment detection--especially regarding using environment variables. (Example)

Thankfully, Laravel 5.0 vastly simplifies environment detection. In 4, you could have multiple environment files based on the environment name (.env.php, .env.local.php, etc.). In all honesty, I never used the environment-specific aspect; I imagine you could theoretically use it to commit all of your environment files to your repo. But since we don't commit any of our environment files, it was a useless distinction--and it forced the delayed loading of the environment file, because it couldn't be loaded until after the environment was detected.

Introducing PHP dotenv

Well, NO MORE. Laravel 5.0 is using PHP dotenv, a proven 3rd-party library that loads from a single .env file.

Every Laravel app now ships with a default .env.example file, which at the moment looks like this:

APP_ENV=local
APP_KEY=SomeRandomString
DB_USERNAME=homestead
DB_PASSWORD=homestead

In order to use this file, just copy it and name the copy .env. Why aren't we renaming the original? You'll see in a second.

Now, you can edit your APP_ENV--which, as you can tell from the default, is the primary way for us to set the application environment name. Check out the newer, simpler environment detection in bootstrap/environment.php:

$env = $app->detectEnvironment(function()
{
    return getenv('APP_ENV') ?: 'production';
});

That's a beautiful thing!

Customizing the example file

So, why are we copying the .env.example instead of just renaming it? Well, imagine your app for a second. Imagine it has a consistent need for 10 environment variables to be defined. Sure, you'll have reasonable fallbacks if they're not defined, but it's still a better deal if you have them all.

Where are you going to store the directions for which variables each app's .env file should set? You could store it in the readme, sure... or you could just update the .env.example file to be the directions for which variables each install of your app should have.

That's it! Need 10 variables for each install? Add those 10 variables to your .env.example file with sensible (or silly) defaults. This file will get committed to your source control, and then each new install can start out by running cp .env.example .env and then customizing .env.

Referencing previous variables

You can learn more from the PHP dotenv docs, but here's a clever note: You can reference environment variables in later environment variables. Check out this example from their readme:

BASE_DIR=/var/webroot/project-root
CACHE_DIR=$BASE_DIR/cache
LOG_DIR=$BASE_DIR/logs

That's clever.

Requiring variables

What if you want to ensure all the required variables are set up front, rather than waiting for the app to break when it accesses them?

Dotenv::required('DB_USERNAME');
// or
Dotenv::required(['DB_HOST', 'DB_NAME', 'DB_USERNAME', 'DB_PASSWORD']);

Done. If it's not defined, it'll throw a RuntimeException.

Conchl

Simple, easy, powerful. And this will completely invalidate all of my blog posts, workarounds, and complaints about environment detection in Laravel. Now it's simple to define your environment name and your environment variables in a single, consistent, predictable manner.


Comments? I'm @stauffermatt on Twitter


Tags: laravel  •  5.0  •  laravel 5