Configuration lives entirely in lf-config/*.php — there’s no .env file. Every file returns a plain PHP array and is read through the framework’s config() helper (e.g. config('database'), config('auth')).
Each file starts with a direct-access guard and should keep it:
defined('APP_PATH') || http_response_code(403).die('403 Direct Access Denied!');
lf-config/app.phpApp-level metadata.
return [
'name' => 'Laika Framework',
'url' => 'https://laikaframework.com',
'documentation' => 'https://docs.laikaframework.com',
];
lf-config/assets.phpWhich static files the framework will hand out. Every request reaches index.php — the rewrite rules do not let the web server serve a file directly — so Laika\Route\Dispatcher is the only gatekeeper, and this file is what it reads.
return [
// Servable extensions. Anything not listed is a 404, whatever directory it
// sits in. That is what keeps .twig sources, .env, lf-logs/*.log and
// lf-storage/keys/app.key unreachable.
'extensions' => [
'css', 'js', 'map',
'jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'ico', 'bmp',
'woff', 'woff2', 'ttf', 'otf',
'mp3', 'wav', 'ogg', 'mp4', 'webm',
'pdf', 'zip', 'txt', 'csv',
],
// Refused everywhere, even if listed above.
'blocked' => ['php', 'phar', 'phtml', 'phps', 'json'],
// Roots written by users rather than by you. Markup served from here is
// stored XSS, so these types are refused inside them.
'untrusted' => [
'roots' => ['uploads'],
'blocked' => ['html', 'htm', 'svg', 'xml'],
],
];
An extension in both extensions and blocked is refused — blocked always wins. Content-Type still comes from Laika\Service\MimeType; note that MimeType::register() only adds a content type, it does not make a type servable. Only this file decides that.
Three rules are enforced in code and no config can loosen them:
| Never served | |
|---|---|
lf-*, vendor/, docs/ |
framework internals — the same list nginx.conf denies |
| any path with a dot segment | .git/, .env, .htaccess |
anything outside APP_PATH |
realpath() resolves .. and symlinks before the check |
Everything else under the project root is servable if its extension passes, so a per-template asset directory such as template/{name}/assets/css/app.css works with no configuration. Rejections are a bare 404, so a forbidden path looks the same as a missing one.
If this file is absent the framework falls back to built-in defaults: every type MimeType knows, minus the php family and html, htm, svg, xml, json — the same set it served before this config existed.
lf-config/database.phpEach top-level key is a connection name. Laika\Model\Model and Laika\Model\Schema\Schema resolve connections by this name ('default' is used when a model doesn’t override it). You can register as many named connections as you need.
return [
'default' => [
'driver' => 'mysql',
'host' => 'localhost',
'port' => 3306,
'database' => 'test',
'username' => 'root',
'password' => '',
],
// Optional — a second connection, e.g. a read replica or another database
'read' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'database' => 'test',
'username' => 'root',
'password' => '',
],
];
See Models & Database for the full query builder and schema builder reference, and the laika-model README for every supported driver (PostgreSQL, SQLite, SQL Server, Oracle, Firebird).
lf-config/mail.phpSMTP/sendmail settings, keyed by driver (sendmail, smtp, mail, qmail). Only driver is required; everything else is commented out with sane defaults until you need SMTP:
return [
'driver' => 'smtp',
'host' => 'smtp.example.com',
'username' => 'user@example.com',
'password' => 'secret',
'port' => 587,
'secure' => 'ssl',
];
lf-config/redis.phpreturn [
'host' => '127.0.0.1',
'port' => 6379,
'prefix' => 'lf',
'password' => '',
];
Used by the Redis session driver and the queue’s redis driver — both read this file as-is; there’s no separate Redis connection to configure per feature.
lf-config/memcached.phpreturn [
'host' => '127.0.0.1',
'port' => 11211,
'prefix' => 'cbm',
'username' => '',
'password' => '',
];
lf-config/queue.phpreturn [
'driver' => 'json', // 'database' | 'redis' | 'json'
'connection' => 'default', // used when driver/failed_driver is 'database'
'failed_driver' => null, // 'database' | 'json' — defaults per 'driver', see below
];
See Queue for the full driver breakdown and how to run php worker.
lf-config/auth.phpGuards, keyed directly by guard name — not wrapped in a 'guards' key. Each entry needs a driver (session, cookie, or token) and a provider (a model class for token, an arbitrary string for session/cookie).
use App\Model\UsersModel;
use App\Model\StaffsModel;
return [
'web' => ['driver' => 'session', 'provider' => 'web'],
'remember' => ['driver' => 'cookie', 'provider' => 'remember'],
'admin' => ['driver' => 'token', 'provider' => StaffsModel::class],
'user' => ['driver' => 'token', 'provider' => UsersModel::class],
];
See Authentication for guard usage.
Not part of lf-config/ by default — laikait/laika-shield reads its own config array via Laika\Shield\ShieldConfig (dot-notation add()/get()/has()), typically loaded from a file you publish yourself. See Security (Shield).
Set via Laika\Service\CORS static setters (merged with framework defaults: X-Content-Type-Options, Referrer-Policy, X-Frame-Options, Content-Security-Policy).
lf-hooks/ and lf-routes/ aren’t config files in the return-an-array sense — they’re plain PHP files auto-loaded on boot. See Hooks and Routing.
Managed via Laika\Service\Local — Local::set('en') / Local::get() / Local::path(...$additional). Files live in lf-lang/ (e.g. en.local.php).