Don't use environment variables outside of config files. But why?
You have probably heard this before, that you should not use env() to retrieve environment variable values outside of your Laravel configs folder. But why? Understanding the why, is always helpful and allows you to make better decisions as an engineer. Let's analyse that!
What's the correct way to retrieve environment variable values?
Suppose you have an environment variable in your .env file:
GOOGLE_API_KEY="something secret here"
First of all, you decided pretty well to add this as an environment variable and not hardcode it inside the code. This is a lot easier to manage on different environments (ex. Production, Staging) and more secure. This value is not being exposed into your git repository.
Now, retrieving this value inside our Laravel app is pretty easy! This can be done using Laravel's helper method env() or using the Env class from Illuminate\Support:
<?php
use Illuminate\Support\Env;
env('GOOGLE_API_KEY')
// or
Env::get('GOOGLE_API_KEY')
So you may think that you can just use the above inside your Controller for example. But that's not a good idea. Ideally you want to have a config file that will retrieve the env variable value, and then you refer to this via the config file.
For example you have a config/services.php config file that has:
<?php
return [
'google' => [
'api_key' => env('GOOGLE_API_KEY')
]
];
And then in your code you get the value using Laravel's config helper or Config facade:
<?php
use Illuminate\Support\Facades\Config;
$googleApiKey = config('google.api_key');
//or
$googleApiKey = Config::get('google.api_key');
Ok but why? Why to use configs as a "proxy" to retrieve my env variables and not just fetch them immediately?
Two main reasons I can think of:
- You get a performance boost
Especially on Production, caching your config files is strongly recommended. You can easily achieve that using Laravel's artisan command:
php artisan config:cache
This actually collects all the configs files and their values, and compiles them to a single php file, which increases performance. That's because number IO operations are decreased to 1, instead of 1 per config file.
That's a great benefit!
The above command also will disable env() function, and will return NULL if you try to use it. So after you have cached your configs, env() is not working more, keep that in mind.
Fetching env variable values using env() is an IO operation. Better this to take place one time on the beginning, instead of doing an IO operation each time you want to fetch an env variable's value. IO ops are expensive and slow and we try to make as less as possible.
Without using configs at all, using env() straight in the code: (Bad)
Request is coming to the Laravel app. Each time env() is called during the request, an IO operation takes place to read the corresponding value from the filesystem.
Using configs, but without caching: (Better)
Request is coming to the Laravel app. Laravel reads/parses/closes X number of config files (X = number of config files you have) and stores their values in memory to continue using them during the request lifecycle. Cool, but we can do better.
Using configs, taking advantage of caching: (Best!)
Framework has already compiled all configs to 1 single file, that contains keys and final values. So it just reads/parses/closes that single file and stores the values in memory to continue accessing them during the request. 🚀
That's a difference!
- Organising / managing becomes easier
You can easily organise your configs however you want. You can name them however you want, put them inside folders, and also structure your config arrays as you want. That will make your codebase cleaner. For example it's way more structured using something like:
<?php
config('services.google.api_key')
than using something like
<?php
env('GOOGLE_API_KEY')
This will allow you to have similar configs in the correct place and not put them randomly in your codebase. It can even guide new developers on where they should put their new values or where they can find grouped configs.
Also I love this dot notation splitting that you can use. Having a structure that makes sense, using nested arrays, is nifty!
And some tips related to config / env variables:
- Don't cache your config in your local environment.
I mean you can, but why to make your life more difficult? If you change something in your .env you have to clear your configs cache using
php artisan config:clear // This will clear the cache completely.
php artisan config:cache // This will re-cache your configs and update the values
for your changes to take place.
Avoid that and keep it simple. Now you can just change something in your .env and immediately get the changes.
We also tend to forget small things like that during development, so there may be times that you are wondering why you get an old value 😢.
- Re-cache your configs in your Production environment
Whether you have a deployment script that deploys your new code to production (strongly recommended), or you do the process manually, always re-cache your configs to gain the free speed performance Laravel offers us. Using:
php artisan config:cache
And you are set! This will ensure that the config cache has been updated with the latest values.