PHPackages                             metalinked/laravel-settings-kit - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Caching](/categories/caching)
4. /
5. metalinked/laravel-settings-kit

ActiveLibrary[Caching](/categories/caching)

metalinked/laravel-settings-kit
===============================

A Laravel package for managing global and user-specific settings with multilingual support, built-in caching, and a full REST API.

v1.2.1(1w ago)0178MITPHPPHP ^8.1|^8.2|^8.3|^8.4CI passing

Since Aug 12Pushed 1w agoCompare

[ Source](https://github.com/metalinked/laravel-settings-kit)[ Packagist](https://packagist.org/packages/metalinked/laravel-settings-kit)[ Docs](https://github.com/metalinked/laravel-settings-kit)[ RSS](/packages/metalinked-laravel-settings-kit/feed)WikiDiscussions main Synced today

READMEChangelog (7)Dependencies (16)Versions (9)Used By (0)

Laravel Settings Kit
====================

[](#laravel-settings-kit)

[![Tests](https://camo.githubusercontent.com/3d42c955bcbf60d19299922dd6d553aaaf044d60ebcfd9a0eed70792b5bfb334/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d6574616c696e6b65642f6c61726176656c2d73657474696e67732d6b69742f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/metalinked/laravel-settings-kit/actions/workflows/tests.yml)[![GitHub Release](https://camo.githubusercontent.com/b8927c4e1c2b899d7f413c194710561a555b09ad9faa2fafca83417f119ddf74/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6d6574616c696e6b65642f6c61726176656c2d73657474696e67732d6b69743f7374796c653d666c61742d737175617265)](https://github.com/metalinked/laravel-settings-kit/releases)[![Total Downloads](https://camo.githubusercontent.com/d2a21c26c49241303e059e23452a1f89534dffdf0f4a6b6e6b51021d88a805d4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d6574616c696e6b65642f6c61726176656c2d73657474696e67732d6b69743f7374796c653d666c61742d737175617265)](https://packagist.org/packages/metalinked/laravel-settings-kit)[![License](https://camo.githubusercontent.com/6c321910620c72bdd25382dcab507a97c4ab47e6ac9e334e009e89169185bf8b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6d6574616c696e6b65642f6c61726176656c2d73657474696e67732d6b69743f7374796c653d666c61742d737175617265)](https://github.com/metalinked/laravel-settings-kit/blob/main/LICENSE.md)

A Laravel package for managing global and user-specific settings with multilingual support, built-in caching, and a full REST API.

Features
--------

[](#features)

- **Two-level settings.** Global defaults with per-user overrides. Users who haven't customised a setting automatically inherit the global default, with no extra queries.
- **Type casting.** Values are stored as strings and automatically cast to `boolean`, `integer`, `json`, `select`, or `string` on retrieval.
- **Built-in cache.** Every read is cached. Changing a global default is immediately visible to all users who haven't customised it.
- **Batch operations.** Update multiple settings in a single call. Retrieve all settings for a user, or only the ones they've personalised.
- **Multilingual labels.** Attach translated titles and descriptions to settings, with locale fallback.
- **Role-based visibility.** Tag settings with a role to control which users see them.
- **REST API.** Full API for SPAs, mobile apps, and headless applications, with token, Sanctum, and Passport authentication.
- **Events.** A `SettingUpdated` event is dispatched on every write and reset, for audit logs and side effects.
- **Blade directive.** `@setting('key')` renders a setting value directly in templates.
- **Artisan commands.** `settings:list`, `settings:export`, `settings:import`, `settings:clear-cache`.

Requirements
------------

[](#requirements)

PHP 8.1 or higher, Laravel 9 or higher.

Installation
------------

[](#installation)

```
composer require metalinked/laravel-settings-kit

php artisan vendor:publish --provider="Metalinked\LaravelSettingsKit\SettingsKitServiceProvider" --tag="migrations"
php artisan migrate
```

Publish the config file (optional):

```
php artisan vendor:publish --provider="Metalinked\LaravelSettingsKit\SettingsKitServiceProvider" --tag="config"
```

Basic Usage
-----------

[](#basic-usage)

```
use Metalinked\LaravelSettingsKit\Facades\Settings;

// Read a global setting
$value = Settings::get('site_name');

// Read a user-specific setting (falls back to the global default if not customised)
$theme = Settings::get('theme', $userId);

// Write a global setting (the preference must exist in the database)
Settings::set('site_name', 'My App');

// Write a user-specific setting
Settings::set('theme', 'dark', $userId);

// Write and auto-create the preference if it does not exist yet
Settings::setWithAutoCreate('new_feature_enabled', true);

// Get or auto-create with a default value
$perPage = Settings::remember('items_per_page', 20);

// Check a boolean setting
if (Settings::isEnabled('maintenance_mode')) {
    abort(503);
}

// Read multiple settings in a single query
$settings = Settings::getMultiple(['theme', 'language', 'timezone'], $userId);

// Update multiple settings in a single call
Settings::setMultiple(['theme' => 'dark', 'language' => 'ca'], $userId);

// Reset a user's customisation, reverting to the global default
Settings::forget('theme', $userId);

// Reset all of a user's customisations at once
$count = Settings::forgetAll($userId);

// Permanently delete a preference and all its user customisations
Settings::delete('old_feature_flag');
```

### Auto-creation and type detection

[](#auto-creation-and-type-detection)

`setWithAutoCreate()` creates the preference automatically if it does not exist, detecting the type from the PHP value:

```
Settings::setWithAutoCreate('maintenance_mode', false); // boolean
Settings::setWithAutoCreate('max_users', 100);          // integer
Settings::setWithAutoCreate('theme_config', ['dark' => true]); // json
Settings::setWithAutoCreate('site_name', 'My App');     // string
```

### Predefined settings (recommended)

[](#predefined-settings-recommended)

For production use, create settings upfront via a seeder so you have full control over type, defaults, and constraints:

```
use Metalinked\LaravelSettingsKit\Models\Preference;

Preference::firstOrCreate(['key' => 'maintenance_mode'], [
    'type' => 'boolean',
    'default_value' => '0',
    'category' => 'system',
    'is_user_customizable' => false,
]);

Preference::firstOrCreate(['key' => 'theme'], [
    'type' => 'select',
    'default_value' => 'light',
    'options' => ['light', 'dark', 'auto'],
    'category' => 'appearance',
    'is_user_customizable' => true,
]);
```

Values for `select` settings are validated on write: passing a value not in `options` throws an `InvalidArgumentException`.

Global vs. User Settings
------------------------

[](#global-vs-user-settings)

The package distinguishes two types of settings based on the `is_user_customizable` column.

**Global unique settings** (`is_user_customizable = false`) apply to the entire application. Calling `Settings::set('maintenance_mode', true)` updates `default_value` directly and affects everyone immediately.

**User-customisable settings** (`is_user_customizable = true`) have a global default that individual users can override. The global default lives in `preferences.default_value`. Per-user overrides are stored in `user_preferences` only when the user actually changes the value, keeping the table lean.

```
// Change the global default (affects all users who have not customised)
Settings::set('theme', 'dark');

// User 123 sets a personal preference (stored in user_preferences)
Settings::set('theme', 'custom', 123);

Settings::get('theme');       // 'dark'  (global default)
Settings::get('theme', 123);  // 'custom' (user override)
Settings::get('theme', 456);  // 'dark'  (inherits global default)
```

### Loading all settings for a user

[](#loading-all-settings-for-a-user)

`allForUser()` is designed for app boot: one query fetches all customisable settings with resolved values and an `is_overridden` flag showing whether the user has personalised each one.

```
$settings = Settings::allForUser($userId, locale: 'ca');
// [
//   'theme' => ['value' => 'dark', 'is_overridden' => true,  'type' => 'select', ...],
//   'language' => ['value' => 'en',   'is_overridden' => false, 'type' => 'string', ...],
// ]
```

To retrieve only the settings a user has explicitly overridden:

```
$overrides = Settings::getUserOverrides($userId);
// ['theme' => 'dark']  (only the keys with a personal override)
```

Multilingual Labels
-------------------

[](#multilingual-labels)

```
Settings::createWithTranslations('notification_email', [
    'type' => 'boolean',
    'default_value' => '1',
    'category' => 'notifications',
], [
    'en' => ['title' => 'Email Notifications', 'text' => 'Receive notifications via email'],
    'es' => ['title' => 'Notificaciones por Email', 'text' => 'Recibir notificaciones por correo'],
    'ca' => ['title' => 'Notificacions per Email', 'text' => 'Rebre notificacions per correu'],
]);

// Retrieve translated labels (falls back to the configured fallback_locale if missing)
Settings::label('notification_email', 'ca');       // 'Notificacions per Email'
Settings::description('notification_email', 'fr'); // fallback to 'en'

// Add translations to an existing setting
Settings::addTranslations('theme', [
    'en' => ['title' => 'Theme', 'text' => 'Choose your preferred theme'],
    'es' => ['title' => 'Tema', 'text' => 'Elige tu tema preferido'],
]);

// Get all settings with translated labels for a locale
$settings = Settings::allWithTranslations('ca');
```

Events
------

[](#events)

A `SettingUpdated` event is dispatched after every `set()` and `forget()` call:

```
use Metalinked\LaravelSettingsKit\Events\SettingUpdated;

Event::listen(SettingUpdated::class, function (SettingUpdated $event) {
    // $event->key, $event->value (null on forget/reset), $event->userId
    Log::info("Setting '{$event->key}' changed", ['value' => $event->value, 'user' => $event->userId]);
});
```

Blade Directive
---------------

[](#blade-directive)

```
@setting('site_name')

```

Artisan Commands
----------------

[](#artisan-commands)

```
# List all settings
php artisan settings:list
php artisan settings:list --category=system
php artisan settings:list --type=boolean

# Export to JSON
php artisan settings:export
php artisan settings:export --file=settings.json --category=system

# Import from JSON
php artisan settings:import settings.json
php artisan settings:import settings.json --force      # overwrite existing
php artisan settings:import settings.json --dry-run    # preview only

# Clear the settings cache (works with any cache driver)
php artisan settings:clear-cache
```

REST API
--------

[](#rest-api)

Enable the API in your `.env`:

```
SETTINGS_KIT_API_ENABLED=true
SETTINGS_KIT_API_AUTH=token
SETTINGS_KIT_API_TOKEN=your-secure-token
```

For local development, you can bypass authentication entirely:

```
SETTINGS_KIT_API_ENABLED=true
SETTINGS_KIT_API_DISABLE_AUTH_DEV=true
```

### Endpoints

[](#endpoints)

```
GET    /api/settings-kit                    List all settings
GET    /api/settings-kit/categories         List categories
POST   /api/settings-kit/preferences        Create a preference

GET    /api/settings-kit/global/{key}       Get a global setting value
POST   /api/settings-kit/global/{key}       Update a global setting value
PUT    /api/settings-kit/global/{key}       Update a global setting value
DELETE /api/settings-kit/global/{key}       Permanently delete a preference

GET    /api/settings-kit/user?user_id=123         All customisable settings for a user (resolved values)
POST   /api/settings-kit/user/batch               Update multiple user settings in one request
DELETE /api/settings-kit/user?user_id=123         Reset all overrides for a user to global defaults

GET    /api/settings-kit/user/{key}?user_id=123   Get a user setting
POST   /api/settings-kit/user/{key}?user_id=123   Update a user setting
PUT    /api/settings-kit/user/{key}?user_id=123   Update a user setting
DELETE /api/settings-kit/user/{key}?user_id=123   Reset a user setting to the global default

```

Query parameters: `locale` (for translated labels), `role`, `category`, `user_id`.

### Authentication

[](#authentication)

ModeConfigUse caseStatic token`SETTINGS_KIT_API_AUTH=token`, `SETTINGS_KIT_API_TOKEN=your-token`Server-to-server integrations (full access)Laravel Sanctum`SETTINGS_KIT_API_AUTH=sanctum`User-facing SPAsLaravel Passport`SETTINGS_KIT_API_AUTH=passport`OAuth applicationsDev bypass`SETTINGS_KIT_API_DISABLE_AUTH_DEV=true`Local development only> **Note:** Token mode grants full access to all users' settings. Use Sanctum or Passport for user-facing APIs where each user should only access their own settings.

### Batch update example

[](#batch-update-example)

```
POST /api/settings-kit/user/batch
{
    "user_id": 123,
    "settings": {
        "theme": "dark",
        "language": "ca",
        "notifications": true
    }
}
```

### Response format

[](#response-format)

All responses include a `success` boolean:

```
{
    "success": true,
    "data": {
        "theme": {
            "value": "dark",
            "is_overridden": true,
            "type": "select",
            "category": "appearance",
            "options": ["light", "dark", "auto"],
            "key": "theme"
        }
    },
    "meta": { "count": 1, "user_id": 123 }
}
```

Error responses:

```
{ "success": false, "error": "Setting not found" }
```

Configuration
-------------

[](#configuration)

```
# Cache (works with any driver: file, database, redis, etc.)
SETTINGS_KIT_CACHE_ENABLED=true
SETTINGS_KIT_CACHE_TTL=3600

# Locale fallback when a translation is missing
SETTINGS_KIT_FALLBACK_LOCALE=en

# API
SETTINGS_KIT_API_ENABLED=false
SETTINGS_KIT_API_PREFIX=api/settings-kit
SETTINGS_KIT_API_AUTH=token
SETTINGS_KIT_API_TOKEN=
SETTINGS_KIT_API_DISABLE_AUTH_DEV=false
SETTINGS_KIT_API_AUTO_CREATE=false
```

Full config reference after publishing (`config/settings-kit.php`):

```
return [
    'cache' => [
        'enabled' => env('SETTINGS_KIT_CACHE_ENABLED', true),
        'ttl'     => env('SETTINGS_KIT_CACHE_TTL', 3600),
        'prefix'  => env('SETTINGS_KIT_CACHE_PREFIX', 'settings_kit'),
    ],
    'tables' => [
        // Warning: 'preferences' is a common table name. Rename if your app
        // already has a table with this name before running migrations.
        'preferences'         => 'preferences',
        'preference_contents' => 'preference_contents',
        'user_preferences'    => 'user_preferences',
    ],
    'fallback_locale' => env('SETTINGS_KIT_FALLBACK_LOCALE', 'en'),
    'user_model'      => 'App\Models\User',
    'api' => [
        'enabled'                    => env('SETTINGS_KIT_API_ENABLED', false),
        'prefix'                     => env('SETTINGS_KIT_API_PREFIX', 'api/settings-kit'),
        'auth_mode'                  => env('SETTINGS_KIT_API_AUTH', 'token'),
        'token'                      => env('SETTINGS_KIT_API_TOKEN'),
        'disable_auth_in_development' => env('SETTINGS_KIT_API_DISABLE_AUTH_DEV', false),
        'auto_create_missing_settings' => env('SETTINGS_KIT_API_AUTO_CREATE', false),
    ],
];
```

Facade Reference
----------------

[](#facade-reference)

MethodDescription`get(key, userId?)`Get a setting value`getMultiple(keys[], userId?)`Get multiple settings in one query`remember(key, default, userId?)`Get a value, auto-creating it with the default if missing`set(key, value, userId?, autoCreate?)`Set a value`setMultiple(keyValues[], userId?)`Set multiple values in one call`setWithAutoCreate(key, value, userId?)`Set a value, creating the preference if needed`isEnabled(key, userId?)`Boolean check`forget(key, userId)`Remove a user's override, reverting to the global default`forgetAll(userId)`Remove all overrides for a user, returns count`delete(key)`Permanently delete a preference and all its data`count(category?, role?)`Count preferences`has(key)` / `exists(key)`Check existence`all(role?, userId?, category?)`All settings as array`allWithTranslations(locale?, role?, userId?, category?)`All settings with translated labels`allForUser(userId, locale?, category?)`All customisable settings for a user, with `is_overridden` flag`getUserOverrides(userId)`Only the settings a user has explicitly overridden`getByCategory(category, userId?, role?)`Settings for a category`getCategories()`Available category names`label(key, locale?)`Translated label`description(key, locale?)`Translated description`create(data[])`Create a preference`createIfNotExists(key, data[])`Create only if absent`createWithTranslations(key, data[], translations[])`Create with i18n content`addTranslations(key, translations[])`Add or update translations`clearAllCache()`Clear all cached values (works with any driver)Testing
-------

[](#testing)

```
composer test
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.

License
-------

[](#license)

MIT © [Metalinked](https://github.com/metalinked)

###  Health Score

47

↑

FairBetter than 93% of packages

Maintenance98

Actively maintained with recent releases

Popularity11

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 78.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~52 days

Recently: every ~72 days

Total

7

Last Release

13d ago

PHP version history (2 changes)v1.0.0PHP ^8.1|^8.2|^8.3

v1.2.0PHP ^8.1|^8.2|^8.3|^8.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/213125150?v=4)[metalinked ](/maintainers/metalinked)[@metalinked](https://github.com/metalinked)

---

Top Contributors

[![oskratch](https://avatars.githubusercontent.com/u/16107567?v=4)](https://github.com/oskratch "oskratch (26 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (7 commits)")

---

Tags

api-restcachinglaravelphppreferencessettingslaravelconfigurationSettingsmultilingualrolespreferencesuser settings

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/metalinked-laravel-settings-kit/health.svg)

```
[![Health](https://phpackages.com/badges/metalinked-laravel-settings-kit/health.svg)](https://phpackages.com/packages/metalinked-laravel-settings-kit)
```

###  Alternatives

[api-platform/laravel

API Platform support for Laravel

58171.6k14](/packages/api-platform-laravel)[hasinhayder/tyro-dashboard

Tyro Dashboard - Beautiful admin dashboard for managing Tyro roles, privileges, users, and settings

5443.8k](/packages/hasinhayder-tyro-dashboard)[tomshaw/electricgrid

A feature-rich Livewire package designed for projects that require dynamic, interactive data tables.

119.4k](/packages/tomshaw-electricgrid)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
