Undertanding the Laravel config part 1: app.php

Published by Andrés López

Undertanding the Laravel config part 1: app.php

When starting a new Laravel application (which gets simpler with each new version), much of Laravel's magic lies in its source code: routing, databases, encryption, design patterns, etc. We know that when working with code, customization is often necessary to adapt tools to your application's requirements.

Laravel offers two ways to do this:

  1. Through the service container (I'll make a future post about this)
  2. Through global configuration files

In this article, we'll explore the app.php configuration file in detail:

return [
    'name' => env('APP_NAME', 'Laravel'),
    'env' => env('APP_ENV', 'production'),
    'debug' => (bool) env('APP_DEBUG', false),
    'url' => env('APP_URL', 'http://localhost'),
    'timezone' => 'UTC',
    'locale' => env('APP_LOCALE', 'en'),
    'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
    'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
    'cipher' => 'AES-256-CBC',
    'key' => env('APP_KEY'),
    'previous_keys' => [
        ...array_filter(
            explode(',', env('APP_PREVIOUS_KEYS', ''))
        ),
    ],
    'maintenance' => [
        'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
        'store' => env('APP_MAINTENANCE_STORE', 'database'),
    ],
];

name

'name' => env('APP_NAME', 'Laravel'),

This is your application's name, generally used as an identifier. Here are some common use cases:

HTML

Recommended to include in your title tag. Many developers (myself included) create layouts like this:

// components/layout/app.blade.php
<!DOCTYPE html>
<html>
    <head>
        <title>
            {{ config('app.name') }} | {{ $title  ?? 'Laravel' }}
    </head>
</html>

Emails

When sending emails, we use the application name as the sender name to build trust. Laravel does this automatically, but you can do it manually, see documentation here:

use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Envelope;

public function envelope(): Envelope
{
    return new Envelope(
        from: new Address('contact@example.com', config('app.name')),
        subject: 'Order Shipped',
    );
}

env

'env' => env('APP_ENV', 'production'),

The environment helps determine your application's context, sometimes we need send emails to the original recipients when we are in prod. Common values:

  • local
  • production
  • staging

Usage examples:

$isProduction = config('app.env') == 'production';

More elegant way:

// Using Laravel's App class
use Illuminate\Support\Facades\App;

if (App::environment('local')) {
    // Local environment
}

or using the app helper:

app()->environment();

app()->environment('local');

app()->environment(['local', 'staging']);

app()->isLocal();

app()->isProduction();

A nice trick to use this is when we are sending email and we don't want send to the orginal recipient, we can add this code in any boot method from service providers:

use Illuminate\Support\Facades\Mail;
 
/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot(): void
{
    if (! $this->app->isProduction()) {
        Mail::alwaysTo('contacto@redplug.com.mx');
    }
}

debug

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

This configuration determines how much error information is displayed to users when issues occur in your application. For local or testing environments, it should be set to true, while in production environments it should always be false.

Error 500 in debug modeError 500 con debug

Error 500 without debug modeError 500 sin debug

This setting is also used by popular debugging packages like:

url

'url' => env('APP_URL', 'http://localhost'),

This setting might seem unimportant at first glance, because when browsing your application, everything appears to work fine even if this value isn't properly set. But there's a catch - we need to understand how Laravel's route generation works. We're all familiar with the route helper - incredibly useful and widely loved. But what exactly does it do? In most cases, it generates an absolute URL for the given route name, for example:

route('brands.index'); // https://myapp.com/brands

However, when working with commands or queue processes, this value isn't available - there's no actual HTTP request. This is where Laravel falls back to using your app.url configuration.

public function handle(): int
{
    $host = config('app.url'); // myapp.com
}

**This is just an example, the actual implementation from the framework it's more advance, if you want to take a look check the code

timezone

This is the timezone your application should use. By default it's set to UTC (Coordinated Universal Time), which serves as the global time standard from which all other timezones are calculated.

This setting is crucial when working with Laravel's date-related features:

  • Carbon
  • Command scheduling
  • Job queues
  • Model timestamps

While it might seem logical to set this to your local timezone (like America/Mexico_City in my case), this isn't actually best practice - especially if your application serves users across different timezones worldwide. Each user will have their own timezone different from your configured one, which is why keeping UTC as your base and converting as needed is the recommended approach:

use Illuminate\Http\Request;
use App\Models\User;

public function index(Request $request)
{
    $user = User::first();

    $localDate = $user->created_at
                        ->format('Y-m-d H:i:s'); // "2025-03-12 01:35:56"

    $clientDate = $user->created_at
                        ->setTimezone('America/Mexico_City')
                        ->format('Y-m-d H:i:s'); // "2025-03-11 19:35:56"

    return response()->json([
        'message' => "The user was created at {$clientDate}"
    ]);
}

locale

'locale' => env('APP_LOCALE', 'en'),

This setting is specific to Laravel and is used to manage global configuration and adjust your application's translations. You can modify this value anywhere in your application using the appropriate methods:

app()->getLocale(); // 'en'

app()->getLocale(); // 'en'

app()->isLocale('en'); // true

app()->setLocale('es'); // configura a español

It's also useful for configuring your HTML to let crawlers know which language your application uses:

// components/layout/app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    ...
</html>

fallback_locale

'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),

If your application doesn't have a proper translation for the current locale, it will fall back to this configuration setting.

faker_locale

'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),

This value is mainly used to seed the database with fake data, using Faker as the data generator:

// en
fake()->name(); // 'Mr. Dejuan Reynolds PhD'

// es
fake()->name(); // 'Jessyca Parisian'

cipher

'cipher' => 'AES-256-CBC',

This is the encryption algorithm your application will use, typically through the Illuminate\Support\Facades\Crypt class. By default it uses AES-256-CBC, currently the most secure option. However, you can change it at any time - just note that any encrypted values in your database will become unusable. The available encryption algorithms are:

  • aes-128-cbc
  • aes-256-cbc
  • aes-128-gcm
  • aes-256-gcm

key

'key' => env('APP_KEY'),

This configuration is tied to the previous one - it's the key/password used for encryption with the selected algorithm. Laravel also uses this setting for generating password reset tokens and signed URLs.

You can typically generate this key securely using the following command:

php artisan key:generate

Note that changing this key will invalidate any records encrypted with the previous key.

previous_keys

'previous_keys' => [
    ...array_filter(
        explode(',', env('APP_PREVIOUS_KEYS', ''))
    ),
],

If you need to change your encryption key - whether as a precaution or because it was publicly exposed - you can perform a gradual migration. Here you can list your previous keys separated by commas. Laravel will attempt each one until finding the correct key. The recommended approach is to prompt users to reset their passwords and other encrypted data so they can be re-encrypted with the new key.

Example how Laravel does this

use lluminate\Encryption\Encrypter;
use Exception;

$key = config('app.key');
$previousKeys = config('app.previous_keys');

$keys = [
    $key,
    ...$previousKeys
];

foreach($keys as $key) {
    try {
        $value = new Encrypter()->decryptString($value);

        return $value;
    }
    catch(Exception $e) {
        continue;
    }
}

throw new Exception('Value can not be decoded');

**This is just an example, the actual implementation from the framework it's more advance, if you want to take a look check the code

maintenance

'maintenance' => [
    'driver' => 'file',
    'store' => 'database',
],

Configure maintenance mode storage, to put your app in maintenance mode you can run:

php artisan down

And for bringing back to live:

php artisan up

Additional configuration options available in Laravel documentation.

When you run this command, a maintenance.php file will be created in storage/framework to handle 503 responses and notify users about maintenance mode.

If you have multiple servers running, you'll need to execute this command on each one. However, if you switch to the cache driver, this can be shared and you'll only need to run it on a single server.

This covers the core configuration options. Future posts will explore additional parameters like frontend_url, asset_url, service providers, and aliases.

Hope you found this deep dive helpful! :)

Andrés López

Andrés López

Laravel lover, Vue enthusiast & writer of everything sounds interesting