Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Settings Laravel Package

outerweb/settings

A Laravel package for managing persistent application settings with typed values, groups, and caching. Define settings in code or the database, then read and write them anywhere via a simple, fluent helper API—ideal for configurable options like site preferences, feature flags, and integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package, publish the migration, and migrate:

composer require outerweb/settings
php artisan vendor:publish --tag="settings-migrations"
php artisan migrate

Publish the config if you need to change the table name or cache behavior:

php artisan vendor:publish --tag="settings-config"

The entire public API is the Settings facade:

use Outerweb\Settings\Facades\Settings;

Settings::set('site_name', 'Acme');
Settings::get('site_name');          // "Acme"
Settings::get('missing', 'fallback'); // "fallback"
Settings::has('site_name');          // true
Settings::forget('site_name');

Where to look first

  1. config/settings.php — table name and caching options.
  2. The published migration — understand the columns (group, key, value, type) because the type column drives casting.
  3. Outerweb\Settings\Settings (the class behind the facade) — the authoritative API surface for your installed version; the README lags releases.
  4. Outerweb\Settings\Models\Setting — see how values are cast on read/write before you store arrays or booleans.

First real use case: a small "general settings" screen — site name, contact email, maintenance-mode toggle, and a JSON array of social links. Seed sensible defaults so get() never surprises you with null in production.

Implementation Patterns

Seed defaults, don't rely on null checks

Create a SettingsSeeder that guards with has() so re-running doesn't overwrite user edits:

foreach ([
    'general.site_name'  => config('app.name'),
    'general.support_email' => '[email protected]',
    'general.maintenance' => false,
] as $key => $value) {
    if (! Settings::has($key)) {
        Settings::set($key, $value);
    }
}

Use dot notation as namespaces

Treat the prefix as a module (general., mail., billing.). It keeps the settings table browsable and makes it trivial to build admin screens per group: fetch Settings::all(), Arr::groupBy on the prefix.

Write in one controller action, validate as a unit

$data = $request->validate([
    'site_name'  => ['required', 'string', 'max:120'],
    'maintenance'=> ['boolean'],
    'links'      => ['array'],
]);

Settings::set('general.site_name', $data['site_name']);
Settings::set('general.maintenance', $request->boolean('maintenance'));
Settings::set('general.links', $data['links'] ?? []);

Pass real booleans and arrays — not "1" or a JSON string. The package infers the type from the value; giving it a string stores a string and you'll fight casts on read.

Wrap it in your own class

A thin wrapper makes the rest of the app testable and greppable:

final class AppSettings
{
    public const SITE_NAME = 'general.site_name';
    public const MAINTENANCE = 'general.maintenance';

    public function siteName(): string
    {
        return Settings::get(self::SITE_NAME, config('app.name'));
    }

    public function maintenanceMode(): bool
    {
        return (bool) Settings::get(self::MAINTENANCE, false);
    }
}

Inject AppSettings rather than calling the facade in controllers, jobs, and middleware. When the package (or its cache) misbehaves, you only have one place to patch, and you can fake it in tests.

Blade

Read settings in a view composer or share them from AppServiceProvider::boot(), not inside templates. The values are cached, but keeping Settings:: calls out of Blade keeps templates dumb and makes it obvious where new keys are introduced:

View::composer('layouts.app', fn ($view) => $view->with([
    'siteName'    => Settings::get('general.site_name', config('app.name')),
    'maintenance' => Settings::get('general.maintenance', false),
]));

Middleware and feature flags

Resolve the flag once per request and stash it on the request or a scoped singleton. Do not re-read the same key in five middleware classes — even cached, it's noise, and it makes the request lifecycle harder to reason about.

Bulk imports

If you ever load settings from a file or another system directly into the DB, go through the facade or explicitly flush the package cache afterwards, otherwise reads keep serving old values until the TTL expires.

Gotchas and Tips

  • Application-wide only. There is no per-user or per-tenant scoping. For model-level settings use a JSON column or a package built for that; don't try to fake tenancy with key prefixes (tenant_42.site_name) — you'll hit cache and cleanup problems.
  • Direct DB edits bypass the cache. UPDATE settings SET value = ... in a console will not invalidate the cached read. Always mutate via Settings::set()/forget(), or clear the cache in the same deploy step.
  • null vs missing. Settings::get('x') returning null can mean "row exists with null value" or "row absent." Use has() when the distinction matters (e.g., "has the admin ever configured this?").
  • Boolean and numeric coercion. Values round-trip through the DB and the type column. A checkbox posting "on" or "0" will store a string unless you cast first. Normalize in the controller: $request->boolean(...), (int), (float).
  • Arrays are JSON. Keep them small, serializable, and free of Eloquent models. If you need structured objects, store IDs and hydrate.
  • Dotted flat keys collide with group parsing. A key literally named foo.bar is indistinguishable from group foo, key bar. Pick one convention (segmented keys only) and enforce it in your settings admin form.
  • Config cache. After publishing and editing config/settings.php (especially the table name), run php artisan config:clear. A stale cached config pointing at the old table produces confusing "missing column" or "all settings are empty" behavior.
  • Migration tags differ by version. If vendor:publish --tag="settings-migrations" reports "no publishable resources," list tags with php artisan vendor:publish and check vendor/outerweb/settings/src/SettingsServiceProvider.php.
  • Tests leak state. The facade reads from the DB and often a cache layer. Use RefreshDatabase and force the array cache driver (or clear the settings cache in setUp) so one test's Settings::set doesn't bleed into the next.
  • Don't store secrets unencrypted. The settings table is plain and frequently dumped to staging. API keys belong in .env/a secrets manager, or at minimum behind an encrypted cast in your own wrapper.
  • Extension points. If you need audit history, encryption, or typed accessors, subclass the Setting model and/or bind your own implementation of the settings class in a service provider rather than patching vendor code. Keep that binding in one provider so upgrades are a single diff.

Overall: excellent fit when you have a handful of global, human-edited configuration values that need to change without a deploy. Poor fit for anything per-entity, high-volume, or secret — recognize that boundary early and you'll avoid most of the gotchas above.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect