Search code examples
phpdockerconfigurationlaravel-6dotenv

How to load multiple .env files or load .env from parent directory in Laravel 6


For a Laravel app using docker-compose I have the following (simplified) folder structure:

Project
|
|-- data
    |-- ...
|-- docker
    |-- ...
|-- laravel
    |-- app
    |-- ...
    |-- .env
|-- docker-compose.yml
|-- .env

Docker-compose is set up to load database connection details from the .env file in the root folder of the project when constructing the containers. Laravel also needs these and I have to duplicate them in the .env file inside the laravel folder.

I would like to avoid this duplication. Ideally I would load both .env files in Laravel to avoid cluttering up the docker-compose .env with stuff that is only relevant to Laravel. But I would be almost as happy to just have the one .env file in the project root, provided there is a clean way to do it.

I have found no configuration setting but relevant methods loadEnvironmentFrom() and useEnvironmentPath() inside the Illuminate\Foundation\Application but I'm not sure where to call them from. I would extend Application, but it seems that Dotenv is already loaded by the time it is instantiated in /boostrap/app.php

Hopefully there is somewhere outside of the vendor dolder where I could change the path or load a different .env file in time for it to be used by the configuration files. Help is greatly appreciated


Solution

  • Use useEnvironmentPath() in bootstrap/app.php:

    $app->useEnvironmentPath($env_path);
    

    Or as a solution:

    $app->useEnvironmentPath(
      dirname(__DIR__, 2)
    );
    

    __DIR__ returns full path of current file (since you are in bootstrap/app.php)
    dirname(__DIR__, 2), goes back 2 steps form your file location (In your case, it returns your Project directory path)

    Now Laravel should read your new .env file.

    -- UPDATE --

    For HTTP applications, update app/Http/Kernel.php :

    use Illuminate\Routing\Router;
    use Illuminate\Contracts\Foundation\Application;
    //////
        /**
         * Create a new HTTP kernel instance.
         *
         * @param  \Illuminate\Contracts\Foundation\Application  $app
         * @param  \Illuminate\Routing\Router  $router
         * @return void
         */
        public function __construct(Application $app, Router $router)
        {
            $app->useEnvironmentPath(dirname(__DIR__, 3));
            parent::__construct($app, $router);
        }
    

    And for console applications, edit app/Console/Kernel.php:

    use Illuminate\Contracts\Events\Dispatcher;
    use Illuminate\Contracts\Foundation\Application;
    
    /////
        /**
         * Create a new console kernel instance.
         *
         * @param  \Illuminate\Contracts\Foundation\Application  $app
         * @param  \Illuminate\Contracts\Events\Dispatcher  $events
         * @return void
         */
        public function __construct(Application $app, Dispatcher $events)
        {
            $app->useEnvironmentPath(dirname(__DIR__, 3));
            parent::__construct($app, $events);
        }
    

    And app/Providers/AppServiceProvider.php:

    public function boot() {
        app()->useEnvironmentPath(dirname(__DIR__, 3));
    }