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

Laravel Settings Laravel Package

larva/laravel-settings

Laravel settings package for storing and retrieving persistent application configuration as key-value pairs, with caching, typed values, and a simple API for managing global settings at runtime.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Pull it in and pin it. Since this isn't a widely adopted package (0 stars, 0 dependents), don't trust ^1.0 ranges. Install explicitly and commit the lockfile:

composer require larvatecn/laravel-settings:^1.0
# then pin the exact resolved version in composer.json

If it isn't on Packagist under that name, add the GitHub repo as a VCS repository and require it by the declared package name in its composer.json.

2. Read src/ before you run anything. This package has no meaningful community footprint, so the source is the documentation. Read these four files first, in order:

  • composer.json — the actual namespace, PHP and Laravel version constraints, and autoload entries.
  • src/*ServiceProvider.php — what gets registered: a singleton, a facade alias, helper files, config merge, publishable assets.
  • config/settings.php — table name, cache key, cache TTL, default driver/column names.
  • database/migrations/* — the schema. This tells you whether it's a plain key/value table or something with group/type/tenant_id columns, which drives everything downstream.

3. Publish and migrate.

php artisan vendor:publish --provider="Larva\Settings\SettingsServiceProvider"
php artisan migrate

Check whether the migration is published (copy into database/migrations) or loaded directly from the package. If it's loaded from the package, you cannot edit it — create your own follow-up migration for any extra columns or indexes.

4. First use case: app-wide branding/feature flags. The lowest-risk first integration is a handful of non-critical, read-heavy values — site name, support email, feature toggles, pagination sizes — read in a view composer or a small SettingsService wrapper. Avoid putting authentication, payment, or routing config in it on day one; you want a week of observing cache behaviour first.

Typical first call, depending on whether the package ships a helper or only a facade:

settings('site.name', 'My App');
// or
Settings::get('site.name', 'My App');

Verify which of these exists — if there's no src/helpers.php in the autoload files array, only the facade is available.

Implementation Patterns

Wrap it, don't sprinkle it. Because the API surface is small and unversioned, put a thin App\Services\Settings class in front of it. All call sites use your class, so if you later swap the package (or vendor it) you change one file:

class Settings
{
    public function get(string $key, mixed $default = null): mixed
    {
        return \Settings::get($key, $default);
    }
}

Dot-notation namespacing. Group keys by domain (billing.currency, mail.from_address, features.new_checkout). Even if the package only stores flat strings, the dots give you a free group prefix you can query with LIKE 'billing.%' when building an admin screen.

Read path: cache-aside with a request-level memo. Most packages in this shape hit cache on get() and the DB on miss. Add your own in-memory array on top so a page rendering 40 settings doesn't do 40 cache round-trips:

private array $memo = [];
public function get(string $key, $default = null) {
    return $this->memo[$key] ??= $this->store->get($key, $default);
}

Write path: set-then-invalidate, in that order, inside a transaction. Any settings module worth using clears its cache key on set(). Confirm it does by reading the setter. If you write to the table directly (seeders, admin panels, tinker), you must call the package's cache-clear or your app serves stale values until TTL expiry.

Seeding defaults. Put canonical defaults in a seeder rather than in a config file, so the admin UI has something to list. Use updateOrCreate on the key column so re-seeding is idempotent.

Admin/back-office integration. A simple SettingsController with a whitelist array of editable keys is safer than a generic "edit any key" form — it prevents typos creating orphan DB rows and prevents accidentally overwriting keys other packages own. Validate every incoming value's type before set(); see type coercion below.

Use it at the boundary, not in the model layer. Hydrating settings inside Eloquent accessors or observers makes tests slow and creates cache coupling with your data layer. Resolve settings in controllers, view composers, jobs, and service providers, then pass plain values downward.

Environment-specific overrides. Keep config/app.php as the source of truth for anything that differs per environment (DB, queue, mail transport). Settings tables should hold user-editable values, not deployment config — otherwise a config:cache in production and a settings row disagree and nobody knows which won.

Testing. In setUp(), clear the package cache and truncate the settings table, or use RefreshDatabase plus an explicit cache flush. If the package caches aggressively, a Cache::flush() in tearDown() avoids cross-test bleed that shows up as flaky assertions.

Gotchas and Tips

Type coercion will bite you. Most key/value settings tables store everything as TEXT. Booleans come back as "1"/"0" or "true", integers as strings, arrays as JSON or PHP-serialized blobs. Decide on one convention and enforce it in your wrapper — cast on read, serialize on write — and never rely on the package to do it. Check whether the migration has a type or payload column; if it does, the package likely handles this for you, but confirm by writing a test.

Dot notation vs. nested arrays is ambiguous. get('mail.from') may mean "the row keyed mail.from" or "index from of the array stored under mail". Read the getter implementation once and document the answer internally; getting surprised by this in production is the single most common failure mode for settings packages.

Cache invalidation is the whole game. Write a failing test that proves stale data is not served: set a value, read it, update the row directly in the DB, then assert the read still returns the old value (that's correct-and-cached) and that calling the package's clear method returns the new one. If the cache key is a single global string, high write frequency will thrash it — batch your writes.

Concurrency. Two admin requests saving different keys simultaneously may clobber if set() does a read-modify-write on a whole JSON blob rather than an updateOrCreate per key. Check the storage model before exposing settings editing to multiple users.

Direct DB writes bypass everything. Seeds, manual SQL, and other tools that touch the table won't fire the package's cache-clearing. Either route all writes through the package or add a model observer that flushes the cache on saved/deleted.

Version and framework compatibility is your problem. Last release 2023-03-10 and zero dependents means nobody is testing this against Laravel 11/12. Before committing, run the test suite against your Laravel version, and check composer.json constraints. If it's capped at ^9.0 or ^10.0, plan to either fork it into packages/ (path repository) or accept a --with-dependencies conflict.

Licence requires a look. The NOASSERTION licence field means the GitHub-detected licence couldn't be identified — there may be no LICENSE file, or a custom one. If this is going into commercial software, read the actual file in the repo root or ask the maintainer. Don't ship on an assumption.

Low bus factor — vendor it if it becomes load-bearing. With zero dependents and a 2023 release, expect no upstream fixes. If settings become critical, copy the src/ and migration into app/ or packages/ with a path repository. The surface area is small enough that this is a few hours' work and removes the supply-chain risk entirely.

Extension points to look for. The service provider likely binds an interface or singleton you can extend() or rebind for a custom store (Redis, per-tenant). If it uses a facade without a container binding, you're stuck with the implementation — another argument for the wrapper class.

Debugging checklist when a value "won't update": (1) is the cache driver the one you think it is — config('cache.default') vs. what you flushed; (2) did the write actually reach the table — check with DB::table(...)->where('key', ...); (3) is a config cache or opcache serving an old class; (4) is another package overriding the same facade alias.

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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core