spatie/laravel-settings
Strongly typed app settings for Laravel stored in databases, Redis, and more. Define settings classes with typed properties, inject them via the container, and read/update values with simple save() calls. Includes migrations, caching, and multiple repositories.
## Getting Started
### Minimal Steps to First Use
1. **Installation**
```bash
composer require spatie/laravel-settings
php artisan vendor:publish --provider="Spatie\LaravelSettings\LaravelSettingsServiceProvider" --tag="migrations"
php artisan vendor:publish --provider="Spatie\LaravelSettings\LaravelSettingsServiceProvider" --tag="config"
php artisan migrate
Create a Settings Class
php artisan make:setting GeneralSettings --group=general
This generates a class in app/Settings/GeneralSettings.php:
class GeneralSettings extends Settings {
public string $site_name = 'My App';
public bool $site_active = true;
public static function group(): string { return 'general'; }
}
Register the Settings Class
Add the class to config/settings.php under the settings array:
'settings' => [
\App\Settings\GeneralSettings::class,
],
Create a Migration
php artisan make:settings-migration CreateGeneralSettings
Define defaults in database/settings/YYYY_MM_DD_CreateGeneralSettings.php:
public function up(): void {
$this->migrator->add('general.site_name', 'My App');
$this->migrator->add('general.site_active', true);
}
Run the migration:
php artisan migrate
Use in Code Inject the settings class into a controller or service:
class HomeController {
public function index(GeneralSettings $settings) {
return view('home', [
'siteName' => $settings->site_name,
'isActive' => $settings->site_active,
]);
}
}
Dependency Injection
class FeatureToggleService {
public function __construct(public FeatureSettings $settings) {}
public function isEnabled(string $feature): bool {
return $this->settings->features[$feature] ?? false;
}
}
Grouping Settings
PaymentSettings, EmailSettings).class PaymentSettings extends Settings {
public string $gateway = 'stripe';
public int $timeout = 30;
public static function group(): string { return 'payment'; }
}
Repository Selection
class CacheSettings extends Settings {
public static function repository(): string { return 'redis'; }
public static function group(): string { return 'cache'; }
}
Validation
class UpdateGeneralSettingsRequest extends FormRequest {
public function rules(): array {
return [
'site_name' => 'required|string|max:255',
'site_active' => 'boolean',
];
}
}
Dynamic Defaults
class AppSettings extends Settings {
public string $env = app()->environment();
public bool $debug = app()->isLocal();
}
Cache Settings: Enable caching in config/settings.php for performance:
'cache' => [
'enabled' => env('SETTINGS_CACHE_ENABLED', true),
'store' => 'redis',
'ttl' => 60, // Cache for 60 seconds
],
Custom Casts: Extend for complex types (e.g., Collection, Carbon):
use Spatie\LaravelSettings\SettingsCasts\SettingsCast;
class JsonArrayCast implements SettingsCast {
public function get($model, string $key, $value, array $attributes) {
return json_decode($value, true);
}
public function set($model, string $key, $value, array $attributes) {
return json_encode($value);
}
}
Register in config/settings.php:
'global_casts' => [
'array' => \App\SettingsCasts\JsonArrayCast::class,
],
Event Listeners: Trigger actions on setting updates:
class SettingsUpdatedListener {
public function handle(SettingsUpdated $event) {
if ($event->settings instanceof GeneralSettings) {
Log::info('General settings updated', $event->changes);
}
}
}
Register in EventServiceProvider:
protected $listen = [
SettingsUpdated::class => [SettingsUpdatedListener::class],
];
Missing Migrations
php artisan migrate after modifying settings classes or migrations.php artisan settings:refresh to regenerate migrations from settings classes.Circular Dependencies
A uses B, B uses A).class A {
public function __construct(public ?B $b = null) {}
}
Repository Mismatches
public static function repository(): string { return 'custom_repo'; }
config/settings.php for repository configurations.Type Safety
string vs int).Cache Invalidation
Settings::forgetCache():
Settings::forgetCache(GeneralSettings::class);
$settings = app(GeneralSettings::class);
dd($settings->toArray()); // Dump all settings
$repository = app(GeneralSettings::class)->getRepository();
dd($repository->getAll());
config/settings.php:
'debug' => env('SETTINGS_DEBUG', false),
Logs will appear in storage/logs/laravel-settings.log.Custom Repositories
Spatie\LaravelSettings\SettingsRepositories\SettingsRepository:
class ApiSettingsRepository implements SettingsRepository {
public function get(string $group, string $key, $default = null) { ... }
public function set(string $group, string $key, $value) { ... }
public function delete(string $group, string $key) { ... }
}
config/settings.php:
'repositories' => [
'api' => [
'type' => \App\SettingsRepositories\ApiSettingsRepository::class,
],
],
Custom Migrations
Spatie\LaravelSettings\Migrations\SettingsMigration for custom logic:
class CustomSettingsMigration extends SettingsMigration {
protected function migrate(): void {
$this->migrator->add('custom.group.key', 'default');
// Custom logic here
}
}
Dynamic Settings
Settings::get() for runtime access:
$value = Settings::get('group.key', 'default');
Settings::set('group.key', $newValue);
Environment-Specific Settings
public function up(): void {
$this->migrator->add('app.debug', app()->isLocal());
}
'cache' => ['enabled' => env('SETTINGS_CACHE_ENABLED', false)],
How can I help you explore Laravel packages today?