.env and the vlucas/phpdotenv library Laravel uses
Concept
Laravel uses vlucas/phpdotenv to load environment variables from a .env file into PHP's $_ENV and $_SERVER superglobals, and into getenv(). This allows configuration to differ between environments (local, staging, production) without changing code.
How it works: At boot time (public/index.php), Dotenv\Dotenv::createImmutable(base_path())->load() reads .env from the project root and calls putenv() for each variable. After loading, env('KEY') reads from $_ENV / getenv().
.env rules:
KEY=value— simple string.KEY=— empty string.KEY="value with spaces"— quote values with spaces.KEY='literal $not interpolated'— single quotes prevent expansion.# comment— comment lines.KEY="${ANOTHER_KEY}/suffix"— variable expansion (phpdotenv 5+).- Never quote boolean values:
APP_DEBUG=true, notAPP_DEBUG="true"(phpdotenv converts to real booleans fortrue,false,null,1,0).
.env.example: A committed template with all keys but no sensitive values. Developers copy it to .env and fill in their values. Never commit .env itself — it contains secrets.
Multiple env files: phpdotenv can load multiple files in order. Laravel also supports .env.testing (loaded when APP_ENV=testing) and .env.{environment} overrides.
Security: Never commit .env. Add .env to .gitignore. Use environment variables in production (from the server, Docker secrets, or a secrets manager) rather than .env files.
Code Example
# .env
APP_NAME="The Framework Architect"
APP_ENV=local
APP_KEY=base64:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
APP_DEBUG=true
APP_URL=http://localhost:8000
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database.sqlite
CACHE_STORE=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
# .env.example — committed, no real values
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=<?php
// Reading env values
$appName = env('APP_NAME'); // "The Framework Architect"
$debug = env('APP_DEBUG'); // true (boolean — not string "true"!)
$dbHost = env('DB_HOST', '127.0.0.1'); // with default if not set
// IMPORTANT: env() should ONLY be called in config files
// Not in controllers, services, or anywhere else!
// Use config() everywhere else:
// config('app.name') reads the value cached from config/app.php
// which reads env('APP_NAME') exactly once at boot
// Why? php artisan config:cache writes all config to a file.
// After caching, .env is NOT read. env() calls outside config files return null!
// WRONG — calling env() outside a config file:
class UserService
{
public function __construct()
{
$this->apiKey = env('API_KEY'); // returns null after config:cache!
}
}
// CORRECT — read from config:
// config/services.php: 'api_key' => env('API_KEY'),
class UserService
{
public function __construct()
{
$this->apiKey = config('services.api_key'); // works always
}
}