Earlier today I got caught out by an interesting little issue when using env()
to access environment configurable values on a deployed Laravel app. Despite having read through the documentation I managed to completely miss the caveat on using this function whilst caching the app’s configuration.
It turns out that if you execute the config:cache
artisan command to cache configuration you can no longer access environment variables using env()
outside of the configuration files in /config
.
When the configuration is cached the .env
file no longer gets loaded. Instead Laravel uses the cached configuration so that the app loads quicker. Obviously something we ideally want to do on a production server; so when deploying an app it is a good idea to run config:cache
. However, the consequence of this is that env()
must not be used anywhere other than within the configuration files.
The Mistake
I was caught out by this today because we had been storing credentials for a payment gateway within the .env
file and then loading them within a class through the constructor something like this:-
public function __construct() {
$this->accountId = env('PAYMENT_GATEWAY_ACCOUNT_ID');
$this->secret = env('PAYMENT_GATEWAY_SECRET');
}
This worked when testing locally, but as soon as we deployed and cached the configuration env('PAYMENT_GATEWAY_ACCOUNT_ID')
and env('PAYMENT_GATEWAY_SECRET')
were both returning null
despite being set in our .env
file on the server.
.env
was no longer being loaded as we were caching the configuration.
The Solution
The fix was to create a new configuration file for our payment gateway and to read the values from .env
in there. For example:-
<?php
// ./config/payment_gateway.php
return [
'account_id' => env('PAYMENT_GATEWAY_ACCOUNT_ID'),
'secret' => env('PAYMENT_GATEWAY_SECRET'),
];
Then our class constructor just needed updating to use the new configuration values using the config()
helper function.
public function __construct() {
$this->accountId = config('payment_gateway.account_id');
$this->secret = config('payment_gateway.secret');
}
Now our environment configurable values for our payment gateway are loaded in correctly when we cache the configuration and can be easily accessed throughout the code.
Re-reading the official documentation this now seems painfully obvious, but it tripped us up at first. I hope by sharing this here it will help others in a similar state of confusion.