Configuration
All application settings live in config/config.php, and every value comes from .env. Copy .env.example to .env and edit that file; you rarely need to touch config.php itself.
cp .env.example .envSettings you will actually change
| What | .env key | Default |
|---|---|---|
| Site URL | APP_URL | http://localhost:8080/ |
| Environment | APP_ENV | production (only exact development enables verbose errors) |
| Database host / name / user / pass | DB_HOST, DB_NAME, DB_USER, DB_PASS | empty (runs without a database) |
Force non-www (1) or www (0) | FORCE_NON_WWW | 1 |
| Asset version | APP_VERSION | time() in development, 1.0.0 otherwise |
| Vite dev server | VITE_DEV_SERVER | empty (uses built assets) |
Leave DB_HOST empty to run without a database. Set APP_VERSION=1.2.3 in production so browsers cache assets; development uses time() automatically for no-cache reloads.
Reading values
Use Config::get() with dot notation anywhere after boot. Missing keys return null.
use Roolith\Configuration\Config;
Config::get('baseUrl'); // e.g. https://example.com/
Config::get('database.host'); // null when no database is configured
Config::get('database') !== null; // testing presence: compare to null, stored null also reads as nullEnvironments
Set the environment in .env and optionally add an override file next to config.php. Values in the environment file win over config.php.
config/config.php
config/development.config.php
config/production.config.php# .env
APP_ENV=development<?php
// config/production.config.php
return [
'database' => [
'host' => 'localhost',
'name' => 'roolith_cms',
'user' => 'root',
'pass' => '',
],
];Config::get('database'); // value from production.config.php when APP_ENV=production
Config::env(); // productionCommon tasks
Change the site URL by setting APP_URL=https://example.com/ in .env. Disable the database by emptying DB_HOST or DB_NAME. Force www with FORCE_NON_WWW=0. Point the frontend at the dev server with VITE_DEV_SERVER=http://localhost:5173 (see Frontend Workflow).
Advanced keys
These keys are optional. You do not need them in config/config.php - setting .env alone takes effect. An omitted key reads as null from Config::get() and the code falls back to Env directly. ConfigValidator skips null and validates present values only. Add a key back only for an explicit config.php override, kept inline with Env::get() and no extra parsing logic.
| Config key | .env key | Default |
|---|---|---|
logPath | LOG_PATH | APP_ROOT/storage/logs/app.log |
logEnabled | LOG_ENABLED | false (0) |
cookiePath | COOKIE_PATH | / |
cookieDomain | COOKIE_DOMAIN | empty (host-only) |
cookieSecure | COOKIE_SECURE | derived from baseUrl scheme |
cookieSameSite | COOKIE_SAMESITE | Lax |
sessionLifetime | SESSION_LIFETIME | 0 (until browser closes) |
trustedProxies | TRUSTED_PROXIES | empty (trust none) |
securityHeaders | SECURITY_HEADERS | true (on) |
logPath
- Env:
LOG_PATH, defaultAPP_ROOT/storage/logs/app.logviaApp\Core\Logger::defaultLogPath() - Allowed: non-empty path, no null bytes, no
..segments;\normalized to/; relative paths resolve againstAPP_ROOT - Override:
'logPath' => Env::get('LOG_PATH', APP_ROOT . '/storage/logs/app.log'),logEnabled
- Env:
LOG_ENABLED, defaultfalse('0') viaApp\Core\Logger::defaultLogEnabled() - Allowed: boolean (
1/0,true/false);falsedrops debug/info/notice, warning and above are always written - Override:
'logEnabled' => filter_var(Env::get('LOG_ENABLED', '0'), FILTER_VALIDATE_BOOLEAN),cookiePath
- Env:
COOKIE_PATH, default'/'viaApp\Core\Session::cookieParams()andApp\Core\Storage::cookieOptions() - Allowed: non-empty string
- Override:
'cookiePath' => Env::get('COOKIE_PATH', '/'),cookieDomain
- Env:
COOKIE_DOMAIN, default''(host-only) viaSessionandStorage - Allowed: string (empty means host-only)
- Override:
'cookieDomain' => Env::get('COOKIE_DOMAIN', ''),cookieSecure
- Env:
COOKIE_SECURE, default derived frombaseUrlscheme viaApp\Core\Session::defaultSecure()(true onhttps, false on plainhttpso local dev works, true whenbaseUrlis missing) - Allowed: boolean; explicit
1/0always wins over derivation - Override:
'cookieSecure' => Env::get('COOKIE_SECURE') !== null ? filter_var(Env::get('COOKIE_SECURE'), FILTER_VALIDATE_BOOLEAN) : \App\Core\Session::defaultSecure(),Set COOKIE_SECURE in .env alone without re-adding the key; re-add the key only for an explicit config.php override, and always derive the default from Session::defaultSecure() instead of hardcoding false so https keeps Secure on by default.
cookieSameSite
- Env:
COOKIE_SAMESITE, default'Lax'viaSessionandStorage - Allowed:
Lax,Strict,None;NonerequirescookieSecure=true(browsers rejectNonewithoutSecure) - Override:
'cookieSameSite' => Env::get('COOKIE_SAMESITE', 'Lax'),sessionLifetime
- Env:
SESSION_LIFETIME, default0viaSession::cookieParams() - Allowed: int
>= 0;0means until the browser closes - Override:
'sessionLifetime' => (int) Env::get('SESSION_LIFETIME', '0'),trustedProxies
- Env:
TRUSTED_PROXIES, default[](trust none, fail-closed) viatrustedProxies()inapp/Utils/functions.phpfalling back toEnv::get('TRUSTED_PROXIES') - Allowed: array of non-empty IP strings; comma-separated env list, exact IP match only, CIDR not supported, invalid IPs filtered out
- Override: prefer the
trustedProxies()fallback over parsing inconfig.php; only add the key manually for an explicit override:
'trustedProxies' => [],# .env
TRUSTED_PROXIES=10.0.0.1,10.0.0.2securityHeaders
- Env:
SECURITY_HEADERS, defaulttrueviaApp\Core\System::sendSecurityHeaders()(is_boolcheck falls back to true) - Allowed: boolean;
falsedisables baseline CSP/nosniff/frame/referrer/HSTS headers - Override:
'securityHeaders' => filter_var(Env::get('SECURITY_HEADERS', '1'), FILTER_VALIDATE_BOOLEAN),Going further
config/config.md is the source mirror for key names and shapes. For .env file format and loading rules, see Using Dot Env.