Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
Laravel Settings
https://github.com/spatie/laravel-settings
Admin
A package that allows you to store strongly typed application settings in a repository like the
...
Tokens:
17,187
Snippets:
139
Trust Score:
-
Update:
1 month ago
Context
Skills
Chat
Benchmark
85.2
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# Laravel Settings Laravel Settings is a PHP package by Spatie that provides strongly typed application settings stored in a repository (database or Redis). It allows you to define settings as PHP classes with typed public properties, automatically handles serialization/deserialization, and integrates seamlessly with Laravel's dependency injection container. The package supports migrations for settings, type casting for complex types (DateTime, Enums, Data Transfer Objects), property encryption, property locking to prevent updates, caching for performance, and auto-discovery of settings classes. Settings classes can be injected anywhere in your Laravel application and updated with a simple save() call. ## Creating a Settings Class Settings classes extend the base `Settings` class and define typed public properties. The `group()` method returns a unique identifier for the settings group. ```php <?php namespace App\Settings; use Spatie\LaravelSettings\Settings; class GeneralSettings extends Settings { public string $site_name; public bool $site_active; public ?string $timezone; public static function group(): string { return 'general'; } } ``` ## Using Settings in Controllers Settings can be injected via constructor or method injection thanks to Laravel's service container. Access properties directly and call save() to persist changes. ```php <?php namespace App\Http\Controllers; use App\Settings\GeneralSettings; use Illuminate\Http\Request; class SettingsController { public function show(GeneralSettings $settings) { return view('settings.show', [ 'site_name' => $settings->site_name, 'site_active' => $settings->site_active, 'timezone' => $settings->timezone, ]); } public function update(Request $request, GeneralSettings $settings) { $settings->site_name = $request->input('site_name'); $settings->site_active = $request->boolean('site_active'); $settings->timezone = $request->input('timezone'); $settings->save(); return redirect()->back()->with('success', 'Settings updated!'); } } ``` ## Creating Settings Migrations Settings migrations define default values for properties. Create migrations using artisan and use the migrator to add, rename, update, or delete properties. ```php <?php use Spatie\LaravelSettings\Migrations\SettingsMigration; return new class extends SettingsMigration { public function up(): void { // Add new properties with default values $this->migrator->add('general.site_name', 'My Application'); $this->migrator->add('general.site_active', true); $this->migrator->add('general.timezone', 'UTC'); } public function down(): void { $this->migrator->delete('general.site_name'); $this->migrator->delete('general.site_active'); $this->migrator->delete('general.timezone'); } }; ``` ## Migration Operations with SettingsBlueprint Use `inGroup()` for cleaner migrations when working with multiple properties in the same group. ```php <?php use Spatie\LaravelSettings\Migrations\SettingsMigration; use Spatie\LaravelSettings\Migrations\SettingsBlueprint; return new class extends SettingsMigration { public function up(): void { $this->migrator->inGroup('general', function (SettingsBlueprint $blueprint): void { // Add properties $blueprint->add('site_name', 'My Site'); $blueprint->add('maintenance_mode', false); // Rename a property $blueprint->rename('old_property', 'new_property'); // Update property value with closure $blueprint->update('site_name', fn(string $name) => strtoupper($name)); // Delete property $blueprint->delete('deprecated_setting'); }); } }; ``` ## Type Casting with DateTime The package automatically casts DateTime properties using the built-in DateTimeInterfaceCast. Works with DateTime, DateTimeImmutable, Carbon, and CarbonImmutable. ```php <?php namespace App\Settings; use DateTime; use Carbon\Carbon; use Spatie\LaravelSettings\Settings; class EventSettings extends Settings { public DateTime $event_start; public ?Carbon $event_end; public \DateTimeImmutable $created_at; public static function group(): string { return 'event'; } } // Usage in migration use Spatie\LaravelSettings\Migrations\SettingsMigration; return new class extends SettingsMigration { public function up(): void { $this->migrator->add('event.event_start', '2024-01-01 10:00:00'); $this->migrator->add('event.event_end', null); $this->migrator->add('event.created_at', now()->toIso8601String()); } }; ``` ## Enum Casting PHP native enums are automatically cast using the EnumCast for both backed and unit enums. ```php <?php namespace App\Settings; use Spatie\LaravelSettings\Settings; enum Theme: string { case Light = 'light'; case Dark = 'dark'; case System = 'system'; } enum NotificationFrequency { case Immediate; case Daily; case Weekly; } class AppearanceSettings extends Settings { public Theme $theme; public NotificationFrequency $notification_frequency; public static function group(): string { return 'appearance'; } } // Migration return new class extends SettingsMigration { public function up(): void { $this->migrator->add('appearance.theme', 'light'); $this->migrator->add('appearance.notification_frequency', 'Daily'); } }; ``` ## Custom Local Casts Define custom casts for specific properties using the `casts()` method in your settings class. ```php <?php namespace App\Settings; use DateTime; use Spatie\LaravelSettings\Settings; use Spatie\LaravelSettings\SettingsCasts\DateTimeInterfaceCast; class ScheduleSettings extends Settings { public $start_date; // Untyped property public $end_date; public static function group(): string { return 'schedule'; } public static function casts(): array { return [ // Cast with explicit type 'start_date' => DateTimeInterfaceCast::class.':'.DateTime::class, // Or instantiate cast directly for additional arguments 'end_date' => new DateTimeInterfaceCast(DateTime::class), ]; } } ``` ## Spatie Laravel Data Integration Cast properties to Data objects from spatie/laravel-data package using the DataCast. ```php <?php namespace App\Settings; use Spatie\LaravelSettings\Settings; use Spatie\LaravelData\Data; class AddressData extends Data { public function __construct( public string $street, public string $city, public string $country, public string $postal_code, ) {} } class CompanySettings extends Settings { public string $name; public AddressData $headquarters; public static function group(): string { return 'company'; } } // Migration return new class extends SettingsMigration { public function up(): void { $this->migrator->add('company.name', 'Acme Inc'); $this->migrator->add('company.headquarters', [ 'street' => '123 Main St', 'city' => 'New York', 'country' => 'USA', 'postal_code' => '10001', ]); } }; ``` ## Encrypting Sensitive Properties Encrypt sensitive properties like API keys by specifying them in the `encrypted()` method. ```php <?php namespace App\Settings; use Spatie\LaravelSettings\Settings; class ApiSettings extends Settings { public string $api_endpoint; public string $api_key; public string $api_secret; public static function group(): string { return 'api'; } public static function encrypted(): array { return [ 'api_key', 'api_secret', ]; } } // Migration with encrypted values return new class extends SettingsMigration { public function up(): void { $this->migrator->add('api.api_endpoint', 'https://api.example.com'); $this->migrator->addEncrypted('api.api_key', 'sk_live_xxxx'); $this->migrator->addEncrypted('api.api_secret', 'secret_xxxx'); } }; ``` ## Locking Properties Lock properties to prevent them from being updated, useful for read-only settings or admin-controlled values. ```php <?php namespace App\Http\Controllers; use App\Settings\GeneralSettings; class AdminSettingsController { public function lockSetting(GeneralSettings $settings) { // Lock single or multiple properties $settings->lock('site_name'); $settings->lock('timezone', 'maintenance_mode'); // Check if locked if ($settings->isLocked('site_name')) { // Property cannot be modified } // Get all locked properties $locked = $settings->getLockedProperties(); // ['site_name', 'timezone', 'maintenance_mode'] // Unlock properties $settings->unlock('site_name'); // Check if unlocked if ($settings->isUnlocked('site_name')) { // Property can be modified } return response()->json(['locked' => $settings->getLockedProperties()]); } } ``` ## Specifying Custom Repository Use different repositories (database or redis) for different settings classes. ```php <?php namespace App\Settings; use Spatie\LaravelSettings\Settings; class CacheSettings extends Settings { public int $ttl; public array $excluded_paths; public static function group(): string { return 'cache'; } // Store these settings in Redis instead of database public static function repository(): ?string { return 'redis'; } } // Migration using specific repository return new class extends SettingsMigration { public function up(): void { $this->migrator->repository('redis'); $this->migrator->add('cache.ttl', 3600); $this->migrator->add('cache.excluded_paths', ['/admin', '/api/health']); } }; ``` ## Faking Settings in Tests Use the fake() method to create test instances with custom values without database interaction. ```php <?php namespace Tests\Feature; use App\Settings\GeneralSettings; use Tests\TestCase; class SettingsTest extends TestCase { public function test_settings_can_be_faked() { // Fake all properties GeneralSettings::fake([ 'site_name' => 'Test Site', 'site_active' => false, 'timezone' => 'America/New_York', ]); $settings = app(GeneralSettings::class); $this->assertEquals('Test Site', $settings->site_name); $this->assertFalse($settings->site_active); } public function test_partial_fake_loads_missing_from_repository() { // Only fake some properties, others loaded from repository GeneralSettings::fake([ 'site_name' => 'Partial Fake', ]); $settings = app(GeneralSettings::class); $this->assertEquals('Partial Fake', $settings->site_name); // site_active loaded from actual repository } public function test_strict_fake_throws_on_missing_properties() { $this->expectException(\Spatie\LaravelSettings\Exceptions\MissingSettings::class); // Pass false to disable loading missing values GeneralSettings::fake([ 'site_name' => 'Strict Fake', ], false); } } ``` ## Listening to Settings Events Subscribe to events for loading and saving settings to add custom logic. ```php <?php namespace App\Listeners; use Spatie\LaravelSettings\Events\LoadingSettings; use Spatie\LaravelSettings\Events\SettingsLoaded; use Spatie\LaravelSettings\Events\SavingSettings; use Spatie\LaravelSettings\Events\SettingsSaved; class SettingsLoadedListener { public function handle(SettingsLoaded $event): void { $settings = $event->settings; $wasFromCache = $event->loadedFromCache; logger()->info('Settings loaded', [ 'class' => get_class($settings), 'from_cache' => $wasFromCache, ]); } } class SavingSettingsListener { public function handle(SavingSettings $event): void { $settings = $event->settings; $newValues = $event->properties; $originalValues = $event->originalValues; // Audit changes $changes = $newValues->diffAssoc($originalValues ?? collect()); logger()->info('Settings saving', [ 'class' => get_class($settings), 'changes' => $changes->toArray(), ]); } } // Register in EventServiceProvider protected $listen = [ SettingsLoaded::class => [SettingsLoadedListener::class], SavingSettings::class => [SavingSettingsListener::class], SettingsSaved::class => [SettingsSavedListener::class], ]; ``` ## Settings as JSON Response Settings classes implement Arrayable, Jsonable, and Responsable interfaces for easy API responses. ```php <?php namespace App\Http\Controllers\Api; use App\Settings\GeneralSettings; class SettingsApiController { public function index(GeneralSettings $settings) { // Return as Laravel response (Responsable interface) return $settings; // Output: {"site_name":"My Site","site_active":true,"timezone":"UTC"} } public function asArray(GeneralSettings $settings) { // Convert to array $array = $settings->toArray(); // ['site_name' => 'My Site', 'site_active' => true, 'timezone' => 'UTC'] // Convert to JSON string $json = $settings->toJson(); // '{"site_name":"My Site","site_active":true,"timezone":"UTC"}' // Convert to Collection $collection = $settings->toCollection(); return response()->json([ 'settings' => $array, 'keys' => $collection->keys(), ]); } } ``` ## Refreshing Settings from Repository Reload settings from the repository to get fresh values after external changes. ```php <?php namespace App\Http\Controllers; use App\Settings\GeneralSettings; class SettingsController { public function refresh(GeneralSettings $settings) { // Get current value $oldName = $settings->site_name; // External process updates the database directly... // Refresh to get new values from repository $settings->refresh(); // Now has fresh values $newName = $settings->site_name; return response()->json([ 'old' => $oldName, 'new' => $newName, ]); } } ``` ## Implementing Custom SettingsCast Create custom casts by implementing the SettingsCast interface for complex types. ```php <?php namespace App\Casts; use Spatie\LaravelSettings\SettingsCasts\SettingsCast; use App\ValueObjects\Money; class MoneyCast implements SettingsCast { protected string $currency; public function __construct(?string $type = null, string $currency = 'USD') { $this->currency = $currency; } public function get($payload): ?Money { if ($payload === null) { return null; } return new Money($payload['amount'], $payload['currency'] ?? $this->currency); } public function set($payload): ?array { if ($payload === null) { return null; } return [ 'amount' => $payload->getAmount(), 'currency' => $payload->getCurrency(), ]; } } // Use in settings class class PricingSettings extends Settings { public Money $minimum_order; public Money $shipping_fee; public static function group(): string { return 'pricing'; } public static function casts(): array { return [ 'minimum_order' => MoneyCast::class, 'shipping_fee' => new MoneyCast(null, 'EUR'), ]; } } ``` ## Artisan Commands Generate settings classes and migrations using built-in artisan commands. ```bash # Create a new settings class php artisan make:setting GeneralSettings --group=general # Create settings class in custom path php artisan make:setting BlogSettings --group=blog --path=app/Settings/Blog # Create a settings migration php artisan make:settings-migration CreateGeneralSettings # Create migration in custom path php artisan make:settings-migration CreateBlogSettings database/settings/blog # Run migrations (includes settings migrations) php artisan migrate # Cache discovered settings classes php artisan settings:discover # Clear discovered settings cache php artisan settings:clear-discovered # Clear settings cache php artisan settings:clear-cache ``` ## Configuration Options The settings.php config file provides extensive customization options for repositories, caching, auto-discovery, and global casts. ```php <?php // config/settings.php return [ // Manually register settings classes 'settings' => [ App\Settings\GeneralSettings::class, App\Settings\BlogSettings::class, ], // Path for generated settings classes 'setting_class_path' => app_path('Settings'), // Paths for settings migrations 'migrations_paths' => [ database_path('settings'), ], // Default repository for settings storage 'default_repository' => 'database', // Repository configurations 'repositories' => [ 'database' => [ 'type' => Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository::class, 'model' => null, 'table' => 'settings', 'connection' => null, ], 'redis' => [ 'type' => Spatie\LaravelSettings\SettingsRepositories\RedisSettingsRepository::class, 'connection' => 'default', 'prefix' => 'settings:', ], ], // Custom encoder/decoder 'encoder' => fn($value): string => json_encode($value), 'decoder' => fn(string $payload, bool $associative) => json_decode($payload, $associative), // Cache configuration 'cache' => [ 'enabled' => env('SETTINGS_CACHE_ENABLED', false), 'store' => null, 'prefix' => 'settings.', 'ttl' => 3600, 'memo' => env('SETTINGS_CACHE_MEMO', false), // Laravel 12.9+ ], // Global casts applied automatically 'global_casts' => [ DateTimeInterface::class => Spatie\LaravelSettings\SettingsCasts\DateTimeInterfaceCast::class, DateTimeZone::class => Spatie\LaravelSettings\SettingsCasts\DateTimeZoneCast::class, Spatie\LaravelData\Data::class => Spatie\LaravelSettings\SettingsCasts\DataCast::class, ], // Auto-discover settings in these paths 'auto_discover_settings' => [ app_path('Settings'), ], // Cache path for discovered settings 'discovered_settings_cache_path' => base_path('bootstrap/cache'), ]; ``` ## Summary Laravel Settings is ideal for managing application-wide configuration that needs to be editable at runtime without code deployments. Common use cases include site settings (name, logo, maintenance mode), feature flags, notification preferences, API configurations, pricing settings, and per-tenant configurations in multi-tenant applications. The typed properties ensure data integrity while the migration system provides version control for settings schema changes. Integration with Laravel is seamless through dependency injection, events, and familiar migration patterns. The package works well with spatie/laravel-data for complex nested settings, supports multiple storage backends (database and Redis), and provides caching for production performance. For testing, the fake() method allows complete control over settings values without touching the repository, making unit and feature tests predictable and fast.