Looking to hire Laravel developers? Try LaraJobs

laravel-settings maintained by abdelhamiderrahmouni

Description
Production ready, super simple settings management for your laravel app.
Last update
2026/04/27 08:45 (dev-main)
License
Links
Downloads
1

Comments
comments powered by Disqus

Laravel Settings

Production-ready, super-simple settings management for Laravel applications.

Store settings in the database with full support for per-user scoping, typed values, caching, and your choice of two definition styles:

  • Enum approach — backed string enums implementing SettingDefinition. Best when you want exhaustive compile-time keys and match-expression defaults.
  • Data Object approach — plain PHP classes extending SettingsData. Best when you want IDE-typed property access and group-level read/write in one call.

Both approaches share the same database table, cache layer, and SettingsManager.

Requirements

  • PHP 8.2+
  • Laravel 11, 12, or 13

Installation

composer require abdelhamiderrahmouni/laravel-settings

Publish and run the migration:

php artisan vendor:publish --tag=settings-migrations
php artisan migrate

Configuration

Publish the config file to customise the cache driver, TTL, cache key prefix, and table name:

php artisan vendor:publish --tag=settings-config
// config/settings.php
return [
    'cache' => [
        'driver' => env('SETTINGS_CACHE_DRIVER', 'file'),
        'ttl'    => env('SETTINGS_CACHE_TTL', 3600),
        'prefix' => env('SETTINGS_CACHE_PREFIX', 'settings'),
    ],
    'table' => env('SETTINGS_TABLE', 'settings'),
];

Approach 1 — Enum

Defining an enum

php artisan settings:make GeneralSettings

This generates app/Settings/GeneralSettings.php. Fill in your cases:

namespace App\Settings;

use Settings\Contracts\SettingDefinition;

enum GeneralSettings: string implements SettingDefinition
{
    case SiteName        = 'site_name';
    case MaintenanceMode = 'maintenance_mode';
    case MaxUploadSize   = 'max_upload_size';

    public function group(): string
    {
        return 'general';
    }

    public function type(): string
    {
        return match ($this) {
            self::SiteName        => 'string',
            self::MaintenanceMode => 'boolean',
            self::MaxUploadSize   => 'integer',
        };
    }

    public function default(): mixed
    {
        return match ($this) {
            self::SiteName        => 'My App',
            self::MaintenanceMode => false,
            self::MaxUploadSize   => 10,
        };
    }

    public function label(): string
    {
        return match ($this) {
            self::SiteName        => 'Site Name',
            self::MaintenanceMode => 'Maintenance Mode',
            self::MaxUploadSize   => 'Max Upload Size (MB)',
        };
    }
}

Supported types: string, integer, boolean, float, array, json.

Reading and writing

use App\Settings\GeneralSettings;
use Settings\Facades\Settings;

// Read — returns the stored value cast to the declared type
Settings::get(GeneralSettings::SiteName);

// Read with a fallback (takes precedence over the enum default)
Settings::get(GeneralSettings::SiteName, 'Fallback');

// Write
Settings::set(GeneralSettings::SiteName, 'My App');
Settings::set(GeneralSettings::MaintenanceMode, true);

// Delete — subsequent get() calls return the enum default
Settings::forget(GeneralSettings::SiteName);

Per-user scoping

Settings::for($user)->get(GeneralSettings::SiteName);
Settings::for($user)->set(GeneralSettings::SiteName, 'Their App');
Settings::for($user)->forget(GeneralSettings::SiteName);

Approach 2 — Data Object

Data Objects give you a fully-typed PHP class where each property is a setting. The IDE knows the exact type of every value. You read and write a whole group at once using fill() and save().

Defining a Data Object

php artisan settings:make GeneralSettings --data

This generates app/Settings/GeneralSettings.php:

namespace App\Settings;

use Settings\SettingsData;

class GeneralSettings extends SettingsData
{
    public function __construct(
        public string $appName = 'My App',
        public bool $maintenanceMode = false,
        public int $maxUploadSize = 10,
        public float $storageQuota = 5.0,
        public array $allowedDomains = [],
    ) {}

    public function group(): string
    {
        return 'general';
    }
}
  • Property types map directly to cast types — no separate type() method needed.
  • Constructor defaults are the fallback values when no DB record exists.
  • The group() method maps to the group column in the settings table.
  • camelCase property names are automatically stored as snake_case in the database (e.g. $appNameapp_name).

Reading settings

use App\Settings\GeneralSettings;
use Settings\Facades\Settings;

$settings = Settings::fill(GeneralSettings::class);

// Each property is typed — full IDE autocomplete
echo $settings->appName;        // string
echo $settings->maintenanceMode; // bool
echo $settings->maxUploadSize;  // int

fill() fetches all stored values for the group in a single query, falls back to constructor defaults for any that have no record, and returns a hydrated GeneralSettings instance.

Writing settings

$settings = Settings::fill(GeneralSettings::class);

$settings->appName = 'New Name';
$settings->maintenanceMode = true;

Settings::save($settings);

save() uses dirty tracking — only properties whose values changed since fill() was called are written to the database. Unmodified properties are not touched.

Per-user scoping

// Read per-user
$settings = Settings::for($user)->fill(GeneralSettings::class);

// Write per-user (only dirty properties saved)
$settings->appName = 'Their App';
Settings::for($user)->save($settings);

Global and per-user records are stored independently.


Choosing an approach

Enum Data Object
Typed return values Cast by type string Native PHP property types
IDE autocomplete on values Requires docblocks Built-in via typed properties
Read a single setting Settings::get() Settings::fill() then access property
Write a single setting Settings::set() Mutate property + Settings::save()
Batch read a group N/A Settings::fill() — one query
Exhaustive compile-time keys Yes (enum cases) No
Labels for UI display Yes (label() method) No (add your own if needed)
Generator command settings:make Name settings:make Name --data

Both approaches coexist in the same application. Use enums for granular, individually-accessed settings and Data Objects for grouped settings you want to work with as a typed unit.


Dependency injection

SettingsManager is bound as a singleton and can be injected directly:

use Settings\SettingsManager;

class UpdateSettingsAction
{
    public function __construct(private readonly SettingsManager $settings) {}

    public function handle(): void
    {
        // Enum approach
        $this->settings->set(GeneralSettings::SiteName, 'My App');

        // Data Object approach
        $data = $this->settings->fill(GeneralSettings::class);
        $data->appName = 'My App';
        $this->settings->save($data);
    }
}

Caching

Settings are cached per-key after the first read. The cache is automatically invalidated on every set(), forget(), and save() call — no manual cache management needed.

Cache keys follow the format {prefix}:{group}.{name} for global settings and {prefix}:{group}.{name}:{user_id} for per-user settings.

Customising stubs

To customise the templates used by settings:make, publish the stubs:

php artisan vendor:publish --tag=settings-stubs

This copies both stubs/settings.stub (enum) and stubs/settings-data.stub (Data Object) into your project root. The settings:make command will prefer your published stubs automatically.

Testing

composer test

License

MIT — see LICENSE for details.