env

Reads an environment variable loaded from .env, returning a default when the key is not set.

Signature
env(string $key, mixed $default = null): mixed

Parameters

ParameterTypeDescription
$$keystringName of the environment variable to read, exactly as it is written in the .env file.
$$defaultoptionalmixed= nullReturned when no environment variable exists for the key. A closure is resolved, so an expensive fallback is only computed when it is needed.

Return value

mixedThe environment variable's value, with the reserved words true, false, null and empty converted to their PHP types; otherwise the default.

Errors

Nothing on its own — an unknown key quietly returns the default; use Illuminate\Support\Env::getOrFail() when a missing variable should raise a RuntimeException instead.

env reads a value that DotEnv loaded from your .env file into the environment repository, falling back to the second argument when the key is not set. It is the bridge between a deployment's secrets and your configuration files, and that is the only place it belongs.

When to reach for it

  • Inside config/*.php, to feed a configuration key from a deployment-specific value.
  • In a package's published config file, so installers can override defaults without editing PHP.
  • In bootstrap/ code that runs before configuration is available.

What trips people up

Values arrive as strings, with a short list of reserved words converted for you: true and (true) become true, false and (false) become false, null and (null) become null, and empty and (empty) become an empty string. Everything else — ports, timeouts, sizes — stays a string, so cast at the config file: (int) env('REDIS_PORT', 6379). A value containing spaces must be wrapped in double quotes.

The second trap is caching. After php artisan config:cache the .env file is never loaded again, so a call from a controller, model or service returns only genuine server-level variables, and null for everything else. Read config('services.stripe.key') in application code instead.

Example

Example · php
<?php

// .env
// APP_NAME="My Application"
// APP_DEBUG=true
// BILLING_CURRENCY=(empty)
// MAIL_REPLY_TO=null

var_dump(env('APP_NAME'));
var_dump(env('APP_DEBUG'));
var_dump(env('BILLING_CURRENCY'));
var_dump(env('MAIL_REPLY_TO'));
var_dump(env('STRIPE_SECRET', 'sk_test'));

// string(14) "My Application"
// bool(true)
// string(0) ""
// NULL
// string(7) "sk_test"

When to use it

  • Point a config key at a per-environment credential, such as env('STRIPE_SECRET') in config/services.php.
  • Give a package a sensible default that operators can override from .env without touching PHP.
  • Flip a feature on per environment with (bool) env('FEATURE_BILLING', false).
  • Cast a numeric setting once, in config, so the rest of the app receives an int rather than a string.

Frequently asked questions

Why does the value come back null in production but work locally?

Because php artisan config:cache was run during deployment, and once the configuration is cached the .env file is no longer loaded. Only real server-level or system-level environment variables are visible; everything else resolves to null. Move the call into a config file and read config('...') from your application code.

Can I call it outside of a config file?

You can, but you should not, in any application that caches its configuration. Calls from controllers, models, jobs, service providers and Blade templates all break the moment config:cache runs. Config files, bootstrap code, and code that runs before the framework boots are the safe places.

How do I get a boolean or an integer out of a .env file?

The literals true, (true), false, (false), null, (null), empty and (empty) are converted to PHP types automatically; every other value is a string. For numbers and anything else, cast where you read it: (int) env('REDIS_PORT', 6379) or (bool) env('FEATURE_FLAG', false).

More examples

The only place it belongs: a config file

The .env value is read once, while the config file is being built, and cast there. Application code then asks for config('billing.retries') and always receives an int — including after php artisan config:cache, when the .env file is no longer loaded.

Example · php
<?php

// config/billing.php
return [
    'secret' => env('STRIPE_SECRET'),
    'currency' => env('BILLING_CURRENCY', 'usd'),
    'retries' => (int) env('BILLING_RETRIES', 3),
    'enabled' => (bool) env('BILLING_ENABLED', false),
];

// Anywhere else in the application, read the cached config instead:
echo config('billing.currency'), PHP_EOL;
var_dump(config('billing.retries'));

// usd
// int(3)

Why the same call breaks in production

Both lines look identical in local development because the .env file is still being parsed on every request. On a deployed server with a cached configuration only the config() call keeps working, which is the single most common source of "it works on my machine" credential bugs.

Example · php
<?php

// app/Services/StripeClient.php
class StripeClient
{
    public function __construct()
    {
        // Works locally. After `php artisan config:cache` on the server,
        // .env is never loaded, so this is null and the client fails.
        $this->secret = env('STRIPE_SECRET');

        // Correct: read the value the config file captured.
        $this->secret = config('billing.secret');
    }
}

echo config('billing.secret') === null ? 'missing' : 'configured', PHP_EOL;

// configured

Failing loudly on a required variable

The helper itself never complains about a missing key, which means a typo in a variable name surfaces as a confusing null far from its cause. Env::getOrFail() turns that into an immediate, named RuntimeException while the config files are being loaded.

Example · php
<?php

use Illuminate\Support\Env;

// config/services.php
return [
    'webhook' => [
        // Optional: falls back silently.
        'timeout' => (int) env('WEBHOOK_TIMEOUT', 10),

        // Required: throws RuntimeException if the variable is unset.
        'signing_key' => Env::getOrFail('WEBHOOK_SIGNING_KEY'),
    ],
];

try {
    Env::getOrFail('WEBHOOK_SIGNING_KEY');
} catch (RuntimeException $e) {
    echo $e->getMessage(), PHP_EOL;
}

// Environment variable [WEBHOOK_SIGNING_KEY] has no value.

Discussion

  • Be the first to comment on this lesson.