A Laravel package for storing and retrieving typed application settings backed by a database, with transparent cache layering and Laravel config fallback.
Laravel config values are read from files at boot time and cannot be changed at runtime. This package solves the problem
by letting you override any config value with a value stored in the database — without a deployment or server restart.
An admin panel, artisan command, or any other runtime code can call set() and the new value is live immediately across
the application.
Settings are defined on a class that extends SettingsDefiniton using #[UseSetting] PHP attributes. Each setting has a key (
matching a Laravel config path), a type, and an optional description.
When a value is read with get(), it is resolved through a three-level chain:
- Cache — served from the cache if present
- Database — read from the
app_settingstable if not cached - Config — falls back to
config($key, $default)if no DB record exists, and caches the result
When a value is written with set(), it is persisted to the database and the cache is updated immediately.
composer require framesnpictures/el-settingsThe package auto-discovers its service provider. Publish the config file and migration, then run the migration:
php artisan vendor:publish --provider="Fnp\Settings\ElSettingsModule" --tag=config
php artisan vendor:publish --provider="Fnp\Settings\ElSettingsModule" --tag=migrations
php artisan migrateThe published config file is config/el-settings.php:
return [
'table' => 'app_settings',
];Change table to use a different database table name.
Create a class extending SettingsDefiniton and annotate it with one #[UseSetting] attribute per setting:
use Fnp\Settings\Base\SettingsDefinition;
use Fnp\Settings\Attributes\UseSetting;
use Fnp\Settings\Enums\ESettingType;
#[UseSetting(config: 'app.name', type: ESettingType::String, description: 'Application name')]
#[UseSetting(config: 'app.debug', type: ESettingType::Bool, description: 'Debug mode')]
#[UseSetting(config: 'app.url', type: ESettingType::EncryptedString, description: 'Application URL')]
#[UseSetting(config: 'mail.port', type: ESettingType::Number, description: 'Mail port')]
#[UseSetting(config: 'app.options', type: ESettingType::Array, description: 'Feature flags')]
class AppSettings extends SettingsDefinition {}The config parameter doubles as both the setting key and the Laravel config path used as a default value. The
description parameter is stored alongside the value in the database, making it easy to identify and manage settings
directly in a database client without needing to cross-reference the source code.
init() syncs the settings class with the database:
- New keys are inserted with the current value from Laravel config as their initial value.
- Existing keys are left untouched — their stored value is never overwritten — but their
descriptionis updated to reflect any changes made in the attribute.
AppSettings::init();Call init() from a database migration every time a #[UseSetting] attribute is added or its description is changed.
This keeps the database in sync with the code automatically on each deployment:
public function up(): void
{
AppSettings::init();
}$name = AppSettings::get('app.name');
// With a fallback default
$timeout = AppSettings::get('app.timeout', 30);AppSettings::set('app.name', 'My App');
AppSettings::set('app.url', 'https://example.com'); // encrypted at rest
AppSettings::set('mail.port', 587);
AppSettings::set('app.options', ['feature_x' => true]);set() validates that the value matches the declared type and throws InvalidArgumentException otherwise.
| Type | Constant | Storage |
|---|---|---|
| Plain string | ESettingType::String |
s column |
| Boolean | ESettingType::Bool |
n column |
| Integer / float | ESettingType::Number |
n column |
| Array | ESettingType::Array |
e column (JSON) |
| Object | ESettingType::Object |
e column (serialized, base64) |
| Encrypted string | ESettingType::EncryptedString |
e column (encrypted, base64) |
Add ModuleSettingsClasses to your module and implement defineSettingsClasses(). This lets the artisan commands
discover available settings classes automatically without requiring a class name argument.
use Fnp\Settings\Features\ModuleSettingsClasses;
class AppModule extends ElModule
{
use ModuleSettingsClasses;
public function defineSettingsClasses(): array
{
return [AppSettings::class];
}
}Treat the above module as a normal Laravel service provider and register it in config/app.php.
See the el-module package for more details.
The class argument is optional when settings classes are registered via ModuleSettingsClasses. If multiple classes
are registered, the command will prompt you to choose one.
Get a value
# Class resolved from registry
php artisan settings:get app.name
# With explicit class
php artisan settings:get app.name --class="App\Settings\AppSettings"Set a value
Pass the value directly on the command line:
php artisan settings:set app.name "My App"
php artisan settings:set mail.port 587
php artisan settings:set app.options '{"feature_x":true}'Or read the value from a file (useful for long strings, certificates, or secrets):
php artisan settings:set app.url --file=/run/secrets/app_urlWith an explicit class:
php artisan settings:set app.name "My App" --class="App\Settings\AppSettings"Initialize settings
When called without --class, settings:init initializes every registered settings class:
# Init all registered classes
php artisan settings:init
# Init a specific class
php artisan settings:init --class="App\Settings\AppSettings"// Read/write directly from cache (bypasses DB)
AppSettings::getCacheValue('app.name');
AppSettings::setCacheValue('app.name', 'value', ttl: 60);
// Read/write directly from the database (bypasses cache)
AppSettings::getDBValue('app.name');
AppSettings::setDBValue('app.name', 'value');
// Read from Laravel config
AppSettings::getConfigValue('app.name', 'default');The MIT License (MIT). Please see License File for more information.