We all know if you want to accelerate performance in Laravel, you can do a lot of things, one of the things is cache what you think, likely route, config, view, etc, but how does it work in Laravel?

To be noticed, cache DOES NOT cache your environment variables, there is documentation in official describe.

Upgrade Guide – Laravel – The PHP Framework For Web Artisans

Caching And Env If you are using the config:cache command during deployment, you must make sure that you are only calling the env function from within your configuration files, and not from anywhere else in your application. If you are calling env from within your application, it is strongly recommended you add proper configuration values to your configuration files and call env from that location instead, allowing you to convert your env calls to config calls.

When you type $ php artisan config:cache what happen to your application?

Calling your binding command class
// Illuminate\Foundation\Console\ConfigCacheCommand

public function handle()
{
    $this->call('config:clear'); // clear your config cached if it exists.

    $config = $this->getFreshConfiguration(); // get a new config

    $configPath = $this->laravel->getCachedConfigPath(); // get cache file path

    $this->files->put(
        $configPath, '<?php return '.var_export($config, true).';'.PHP_EOL
    ); // put the cached file.

    try {
        require $configPath; // if it generated successful, require the file.
    } catch (Throwable $e) { // php7 error exception handle.
        $this->files->delete($configPath); // delete failed file.

            // throwing a logic exception to tell you, oh, something wents wrong.
        throw new LogicException('Your configuration files are not serializable.', 0, $e);
    }

        // otherwise it's successful.
    $this->info('Configuration cached successfully!');
}

Next, we explore the method getFreshConfiguration

protected function getFreshConfiguration()
{
    $app = require $this->laravel->bootstrapPath().'/app.php'; // require application kernel of laravel.

    $app->useStoragePath($this->laravel->storagePath()); // storage path.

    $app->make(ConsoleKernelContract::class)->bootstrap(); // bootstraping instanced of ConsoleKernelContract class.

    return $app['config']->all(); // get all of config variables.
}

To see getCachedConfigPath and normalizeCachePath

// Illuminate\Foundation\Application

public function configurationIsCached()
{
    return file_exists($this->getCachedConfigPath());
}

public function getCachedConfigPath()
{
    return $this->normalizeCachePath('APP_CONFIG_CACHE', 'cache/config.php');
}

protected function normalizeCachePath($key, $default)
{
    if (is_null($env = Env::get($key))) {
        return $this->bootstrapPath($default);
    }

    return Str::startsWith($env, '/')
            ? $env
            : $this->basePath($env);
}

// Deal with your bootstrap path
public function bootstrapPath($path = '')
{
    return $this->basePath.DIRECTORY_SEPARATOR.'bootstrap'.($path ? DIRECTORY_SEPARATOR.$path : $path);
}

// Deal with your base path
public function basePath($path = '')
{
    return $this->basePath.($path ? DIRECTORY_SEPARATOR.$path : $path);
}

But here is a problem, the laravel how to know to load your configs cached or not?

// Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables
public function bootstrap(Application $app)
{
    if ($app->configurationIsCached()) { // if it cached, return empty
        return;
    }

    $this->checkForSpecificEnvironmentFile($app);

    try {
        $this->createDotenv($app)->safeLoad();
    } catch (InvalidFileException $e) {
        $this->writeErrorAndDie($e);
    }
}

// check environment.
protected function checkForSpecificEnvironmentFile($app)
{
    if ($app->runningInConsole() && ($input = new ArgvInput)->hasParameterOption('--env')) {
        if ($this->setEnvironmentFilePath(
            $app, $app->environmentFile().'.'.$input->getParameterOption('--env')
        )) {
            return;
        }
    }

    $environment = Env::get('APP_ENV');

    if (! $environment) {
        return;
    }

    $this->setEnvironmentFilePath(
        $app, $app->environmentFile().'.'.$environment
    );
}

And now we return back to see getFreshConfiguration and you are seeing

$app->make(ConsoleKernelContract::class)->bootstrap();
//Illuminate\Foundation\Console\Kernel <-- instance of ConsoleKernelContract
protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, //HERE
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    \Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
];

public function bootstrap()
{
    if (! $this->app->hasBeenBootstrapped()) {
        $this->app->bootstrapWith($this->bootstrappers()); //bootstrapping.
    }

    $this->app->loadDeferredProviders();

    if (! $this->commandsLoaded) {
        $this->commands();

        $this->commandsLoaded = true;
    }
}

Next, seeing Illuminate\Foundation\Bootstrap\LoadConfiguration::class

// Illuminate\Foundation\Bootstrap\LoadConfiguration

public function bootstrap(Application $app)
{
    $items = [];

    // First we will see if we have a cache configuration file. If we do, we'll load
    // the configuration items from that file so that it is very quick. Otherwise
    // we will need to spin through every configuration file and load them all.

        // Here is the key, if cached file exists, require it. ^^^ see upon description.
    if (file_exists($cached = $app->getCachedConfigPath())) {
        $items = require $cached;

        $loadedFromCache = true;
    }

    // Next we will spin through all of the configuration files in the configuration
    // directory and load each one into the repository. This will make all of the
    // options available to the developer for use in various parts of this app.
    $app->instance('config', $config = new Repository($items));

    if (! isset($loadedFromCache)) {
        $this->loadConfigurationFiles($app, $config);
    }

    // Finally, we will set the application's environment based on the configuration
    // values that were loaded. We will pass a callback which will be used to get
    // the environment in a web context where an "--env" switch is not present.
    $app->detectEnvironment(function () use ($config) {
        return $config->get('app.env', 'production');
    });

    date_default_timezone_set($config->get('app.timezone', 'UTC'));

    mb_internal_encoding('UTF-8');
}

For now, we all knew how does it work about config cache, at last, I found a tip about load bootstrap loading. If you want to load the environment after bootstrapping, you can use afterLoadingEnvironment closure.

public function afterLoadingEnvironment(Closure $callback)
{
    return $this->afterBootstrapping(
        LoadEnvironmentVariables::class, $callback
    );
}

Cheers!