Environment variables and configurations in Laravel

Video thumbnail

Content Index

When we develop an application in Laravel, it is normal for certain values to change depending on the environment: database credentials, external services, debug mode, or URLs. This is where environment variables in Laravel come into play, a key piece for keeping code clean, secure, and easy to deploy.

However, although Laravel makes their use very easy, it is also common to see serious errors (especially in production) due to not fully understanding when to use env(), when to use config(), and what happens when caching the configuration. In this article, I explain all of that with practical examples and real-world usage criteria.

Environment variables are ideal for when we want to test multiple configurations in a project quickly, or when several people are developing on the same project and have different project configurations. In other words, they offer an agile and fast approach to accessing multiple configurations, but this can also bring drawbacks. Being able to change or delete environment variables by mistake from a single file can cause problems when switching from one mode to another without realizing it or deleting an environment variable required by the project; therefore, using them in production can lead to problems precisely because of this freedom.

Configuration files are excellent for holding the final production configurations of the project. Therefore, we should use environment variables in development and configurations in production. This is something the framework already tells us, as if we look at some configurations, we will often see a scheme like the following:

What is an environment variable in Laravel?

An environment variable is a value external to the code that is loaded at runtime and allows for modifying the application's behavior without touching the PHP files.

In Laravel, these variables are normally defined in the .env file and are loaded thanks to the PHP Dotenv component.

Why Laravel separates configuration and code

Laravel follows a fundamental best practice of modern development:
code should not change between environments, configuration should.

Thanks to this:

  • The same code can run on local, staging, or production.
  • Credentials are not uploaded to the repository.
  • Deployments are more secure and predictable.

One of the big problems in software development occurs when we are developing an application and periodically pushing modules to production: publishing our development-only configurations along with these changes. This can be solved with the previously presented scheme simply by avoiding uploading the .env file to production and maintaining production values in the corresponding configuration files.

This does not mean that it is not recommended or professional to use environment variables in production; it should be avoided where possible, but you can use them with extreme care, keeping a minimum number of environment variables in production that may be essential to keep things as controlled as possible.

Another good use of environment variables in production is when we make major changes to the project and upload it to production, or if there is a production error that is difficult to fix through log viewing and therefore we want to test in production if everything developed works as expected. In these cases, you can uncomment the environment variables in production:

.env

APP_ENV=local APP_DEBUG=true

Test the system on the server, and when we see that everything is working as expected, comment them out again:

.env

# APP_ENV=local # APP_DEBUG=true

With this, you avoid touching the project configurations again, which are files that must be handled with extreme care.

What type of data should go in environment variables

Some clear examples:

  • Database credentials
  • API keys (Mailgun, AWS, Stripe…)
  • Cache, queue, or session drivers
  • Flags like APP_ENV or APP_DEBUG

The .env file in Laravel

What the .env file is for

The .env file is where we define the local environment variables of the project, following the format:

KEY=VALUE

Laravel automatically loads this file when the application starts.

Differences between .env and .env.example

  • .env
    • Contains real values
    • Should never be uploaded to the repository
  • .env.example
    • Is versioned
    • Serves as a template
    • Indicates which variables are necessary

Keeping an updated .env.example avoids many problems when someone new clones the project or when it is deployed in a new environment.

Why the .env file should not be uploaded to the repository

Uploading the .env implies:

  • Exposing credentials
  • Forcing development configurations onto production
  • Very serious security risks

Laravel already assumes that the .env is private, which is why it is ignored by default in .gitignore.

How Laravel works internally with environment variables

Since Laravel 5, the framework uses PHP Dotenv to load variables from the .env and expose them to PHP through $_ENV.

How and when variables are loaded

Variables are loaded:

  • When the application starts
  • Before configuration files are read

That's why you will see many lines like this in config/*.php:

'debug' => env('APP_DEBUG', false),

This is safe even with cached configuration.

Types of values supported in the .env

Laravel interprets some special values:

| Value in `.env` | Real type |
| --------------- | ------------ |
| true / false | boolean |
| null | null |
| empty | empty string |
 

You can also use quotes if there are spaces:

APP_NAME="My Application"

env() vs config(): the difference that avoids production errors

This is one of the most important parts of the article.

When to use env()

Only inside configuration files (config/*.php)

Correct example:

// config/app.php 
'env' => env('APP_ENV', 'production'),

Why you should not use env() outside of configuration files

When you run:

$ php artisan config:cache

Laravel:

  • Combines all configuration into a single file
  • Stops loading the .env

At that point, any env() used outside of config may return null.

In production, this causes bugs that are hard to trace.

More than once, I have found production bugs caused exactly by this.

How to correctly consume configuration with config()

The correct way is:

  • Read env() in config/*.php
  • Use config() in the rest of the application
  • config('app.env');

Environment variables in development and production

Recommended use in development

In development, the .env is ideal:

  • Quick changes
  • Multiple configurations
  • Total flexibility

There is no problem modifying variables frequently here.

Risks of using .env directly in production

In production, the .env:

Is easy to modify by mistake

  • Is not versioned
  • Can break the system without leaving a clear trace
  • Therefore, in my experience, the final production configuration should live in config/*.php, not depend on an editable .env.

Exceptional cases and how to handle them with care

There are specific cases (complex errors, urgent validations) where it might be useful to temporarily activate:

APP_ENV=local APP_DEBUG=true

Test, verify, and deactivate it again immediately.

It is a valid technique, but only if you know exactly what you are doing.

Configuration cache and its impact on environment variables

What php artisan config:cache actually does

  • Generates a single file with all the configuration
  • Improves performance
  • Disables loading of the .env

What happens to env() when configuration is cached

It will only work with system environment variables, not those from the .env.

That is why Laravel clearly warns:

Never use env() outside of configuration files.

Common errors when deploying to production

  • Caching configuration and then changing the .env
  • Using env() in controllers or services
  • Forgetting to clear the cache (config:clear)

Creating custom configurations in Laravel

It is possible to create custom configurations for our application, which is extremely useful for personalizing these parameters when necessary. For example, if you want to install an electronic wallet like PayPal that requires defining access keys, it is highly recommended to manage these accesses through configurations to be able to edit them more easily. They are also useful if we need to create any additional parameter for the correct operation of the application.

To do this, we must select the configuration file where we want it to be hosted. Here, it is recommended that you choose the one that most closely resembles the configuration to be created. For example, if you want to use keys to access Dropbox or Google Drive, you can choose database.php or app.php. If they are social login credentials, you can use auth.php, for example.

When it makes sense to create your own configuration

For example:

  • Keys for external services
  • Custom flags
  • Business-specific parameters

Where to locate it within the config folder

The ideal is:

  • Use an existing file if it fits (app.php, services.php)
  • Create a new one if necessary

Just like existing configurations, it is possible to use the helper function env() so that it takes the value from the .env if it exists there:

// config/custom.php return [ 'route' => env('APP_ROUTE', 'production'), ];

How to read these configurations from the application:

config('custom.route');

This approach is much safer than using env() directly.

Example

config\app.php

'app_route' => env('APP_ROUTE', "production"),

.env

APP_ROUTE=local

To access these configurations, we use the helper function config():

config('app')['env']

In which the first parameter specifies the name of the configuration file and the next parameter the key:

config('app')['env']

We could also directly reference the environment variable:

env('APP_ROUTE', "production")

Validating environment variables and avoiding silent failures

Typical problems when a variable is missing

  • Null values
  • Runtime errors
  • Hard-to-reproduce bugs

Using Env::getOrFail from Laravel 10 onwards

Laravel 10 introduces a very useful method:

use Illuminate\Support\Env; Env::getOrFail('MAILGUN_SECRET');

If the variable does not exist, it throws an exception immediately.

This allows detecting errors at startup, not when something critical has already failed.

Detecting errors as soon as possible

This approach is ideal for:

  • Production
  • External services
  • Critical configuration

Managing multiple environments in Laravel

APP_ENV and environment detection

Laravel detects the environment with APP_ENV:

App::environment('local');

.env files per environment

Laravel supports:

  • .env
  • .env.staging
  • .env.testing

This makes it easier to work with multiple environments without mixing configurations.

Creating custom files

In case it is necessary, we can create custom configuration files; we simply must create the file inside the config folder of the project, in which we must have the same structure as the current ones, for example:

config\custom.php

<?php 
  return [ 'test_config' => env('TEST_CONFIG', 'VALUE'), ];

And to access the custom file, we do it in the same way as with the current configuration files:

config('custom');

Best practices for teams and deployments

  • .env.example always updated
  • Minimum variables in production
  • Cached configuration on deploy

Final best practices for environment variables in Laravel

Quick checklist for production

  • ✅ .env out of the repository
  • ✅ env() only in config
  • ✅ config() in the rest of the code
  • ✅ config:cache in production
  • ✅ Validation of critical variables

Errors you should avoid:

  • Using env() in controllers
  • Activating APP_DEBUG in production
  • Depending on .env for critical logic

Recommendations based on real experience

Centralizing configuration and minimizing the .env in production makes deployments more secure, predictable, and easier to maintain.

Frequently Asked Questions about environment variables in Laravel (FAQ)

  • Should I upload the .env file to the repository?
    • No. Never.
  • Can I use environment variables in production?
    • Yes, but with extreme care and only the minimum necessary.
  • What happens if I use env() with config:cache?
    • You will probably get null values.
  • Is Env::getOrFail better than env()?
    • For critical variables, yes.

Conclusion

Environment variables in Laravel are a powerful tool, but when misused, they can become a constant source of errors, especially in production.

Understanding the difference between .env, env(), and config(), along with the impact of config:cache, marks the difference between a fragile project and a professional one.

If you apply these best practices, your application will be more secure, maintainable, and prepared to grow.

We will see how to create custom variables, as well as files and recommendations when using custom configurations and environment variables.

I agree to receive announcements of interest about this Blog.

Andrés Cruz

ES En español