codersandip / laravel-dynamic-settings
A professional Laravel package to store and manage application settings dynamically using the database with caching, multi-tenant support, and an admin panel UI.
Package info
github.com/codersandip/laravel-dynamic-settings
Language:Blade
pkg:composer/codersandip/laravel-dynamic-settings
Requires
- php: ^8.1
- illuminate/cache: ^10.0|^11.0|^12.0
- illuminate/console: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- mockery/mockery: ^1.5
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
README
A professional Laravel package to store and manage application settings dynamically using the database instead of config files. Supports automatic caching, multi-tenant scoping, per-user overrides, and a beautiful admin panel UI.
Features
- 📦 Database-driven settings — store any key/value with type casting
- ⚡ Automatic caching — configurable driver and TTL, cache invalidated on update
- 🏢 Multi-tenant support — tenant-scoped settings with global fallback
- 👤 Per-user overrides — priority: user → tenant → global
- 🎨 Admin Panel UI — dark-mode Bootstrap 5 CRUD interface with search, filter, toggles
- 🔄 Inline editing — AJAX quick-update widget on the edit page
- 🛡️ Type support —
string,integer,float,boolean,json - 🖥️ Artisan commands —
settings:cache,settings:clear,settings:seed - ✅ Fully tested — PHPUnit test suite included
Requirements
- PHP 8.1+
- Laravel 10.x / 11.x / 12.x
Installation
1. Install via Composer
composer require codersandip/laravel-dynamic-settings
Laravel auto-discovers the service provider. No manual registration needed.
2. Publish assets
Publish everything at once:
php artisan vendor:publish --tag=settings-all
Or selectively:
# Config only php artisan vendor:publish --tag=settings-config # Migrations only php artisan vendor:publish --tag=settings-migrations # Views only php artisan vendor:publish --tag=settings-views # Routes only php artisan vendor:publish --tag=settings-routes
3. Run migrations
php artisan migrate
4. (Optional) Seed default settings
php artisan settings:seed
Configuration
After publishing, edit config/settings.php:
return [ // Cache driver (file, redis, memcached, array) 'cache_driver' => env('SETTINGS_CACHE_DRIVER', 'file'), // Cache TTL in seconds (3600 = 1 hour) 'cache_ttl' => env('SETTINGS_CACHE_TTL', 3600), // Cache key prefix 'cache_prefix' => env('SETTINGS_CACHE_PREFIX', 'dyn_setting'), // Admin panel URL prefix 'route_prefix' => env('SETTINGS_ROUTE_PREFIX', 'admin/settings'), // Middleware applied to admin routes 'route_middleware' => ['web', 'auth'], // Available groups in the dropdown 'groups' => ['general', 'email', 'payment', 'security'], ];
You can also set these in your .env file:
SETTINGS_CACHE_DRIVER=redis SETTINGS_CACHE_TTL=7200 SETTINGS_ROUTE_PREFIX=dashboard/settings
Usage
Helper Function
// Get a setting setting('site_name'); // → 'My Application' // Get with a default value setting('site_name', 'Default App'); // → 'Default App' if not set // Get with tenant context (falls back to global if not found) setting('currency', 'USD', $tenantId); // Get with tenant + user context setting('theme', 'light', $tenantId, $userId);
Set a Setting
// Via helper (chained) setting()->set('site_name', 'My App'); // With options setting()->set('page_size', 20, [ 'type' => 'integer', 'group' => 'general', 'description' => 'Results per page', ]);
Facade
use Codersandip\DynamicSettings\Facades\Settings; Settings::get('site_name'); Settings::get('site_name', 'Default'); Settings::set('site_name', 'New Name'); Settings::delete('site_name'); Settings::has('site_name');
Service (Dependency Injection)
use Codersandip\DynamicSettings\Services\SettingsService; class MyController extends Controller { public function __construct(private SettingsService $settings) {} public function index() { $siteName = $this->settings->get('site_name', 'My App'); // ... } }
Data Types
| Type | PHP Type | Storage | Example |
|---|---|---|---|
string |
string |
As-is | "Hello World" |
integer |
int |
Numeric string | 42 |
float |
float |
Numeric string | 3.14 |
boolean |
bool |
"1" / "0" |
true / false |
json |
array |
JSON string | ["stripe", "paypal"] |
setting()->set('enabled', true, ['type' => 'boolean']); setting()->set('count', 100, ['type' => 'integer']); setting()->set('gateways', ['stripe', 'pp'], ['type' => 'json']); setting('enabled'); // → true (bool) setting('count'); // → 100 (int) setting('gateways'); // → ['stripe', 'pp'] (array)
Multi-Tenant Support
Settings resolve with this priority: user → tenant → global
// Store global setting setting()->set('currency', 'USD'); // Store tenant-specific override setting()->set('currency', 'GBP', ['tenant_id' => 5]); // Store user-specific override (within a tenant) setting()->set('currency', 'EUR', ['tenant_id' => 5, 'user_id' => 12]); // Retrieval setting('currency'); // → 'USD' (global) setting('currency', null, 5); // → 'GBP' (tenant 5 override) setting('currency', null, 5, 12);// → 'EUR' (user 12 override) setting('currency', null, 5, 99);// → 'GBP' (user 99 falls back to tenant) setting('currency', null, 9); // → 'USD' (tenant 9 falls back to global)
Fluent API
use Codersandip\DynamicSettings\Facades\Settings; // Set tenant context once $tenantSettings = Settings::forTenant(5); $tenantSettings->get('currency'); // uses tenant 5 $tenantSettings->get('locale'); // Chain tenant + user Settings::forTenant(5)->forUser(12)->get('theme');
Artisan Commands
| Command | Description |
|---|---|
settings:cache |
Pre-warm cache with all settings from DB |
settings:clear |
Flush the settings cache |
settings:seed |
Seed a set of default settings |
php artisan settings:cache
php artisan settings:clear
php artisan settings:seed
php artisan settings:seed --force # overwrite existing settings
Admin Panel
Access the admin panel at /admin/settings (configurable via route_prefix).
The panel includes:
- 📋 Index — list all settings with search, group/type filter, boolean toggles
- ➕ Create — add a new setting with type, group, scope options
- ✏️ Edit — update a setting, with inline AJAX quick-update widget
- 🗑️ Delete — remove a setting (with confirmation)
Protecting the Admin Panel
Set the middleware in config/settings.php:
'route_middleware' => ['web', 'auth', 'can:manage-settings'],
Or disable the built-in routes and define your own:
// config/settings.php 'disable_routes' => true,
Then publish routes:
php artisan vendor:publish --tag=settings-routes
And register the file in bootstrap/app.php or routes/web.php.
Database Schema
settings
├── id (bigint, auto-increment)
├── key (varchar 191, indexed)
├── value (longtext, nullable)
├── type (varchar 20 — string|integer|float|boolean|json)
├── group (varchar 50, indexed, default: general)
├── tenant_id (bigint unsigned, nullable, indexed)
├── user_id (bigint unsigned, nullable, indexed)
├── description (varchar, nullable)
├── is_public (boolean, default: false)
├── created_at
└── updated_at
UNIQUE (key, tenant_id, user_id)
Testing
composer test
Changelog
See CHANGELOG.md.
License
The MIT License (MIT). See LICENSE for details.
Author
Sandip — contact@codersandip.com
GitHub: github.com/codersandip