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

pharaonic/laravel-settings

A Laravel package for managing application settings through a simple, flexible API. Persist configuration values in the database, retrieve them easily at runtime, and organize settings cleanly for small apps or larger projects that need centralized control.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What it is. A thin key/value settings store: one publishable migration, a service-provider binding, a facade, caching, and type-aware get/set helpers, plus a "settings for model objects" mode (almost certainly a polymorphic relation, though the assessment notes never confirm the schema — verify against the migration before assuming).

Architecture fit. This is cross-cutting infrastructure, not domain logic. It belongs in the same layer as config() — read by application services and delivery code, owned by no bounded context. That makes the fit easy but also low value: anything you gain by adopting it, you can replicate with a ~150-line model + cache decorator. There is no architectural lock-in, which is the single most important fact for a TPM decision here.

  • Fit: good for runtime-mutable, application-wide flags and options (feature toggles, per-tenant display preferences, operational knobs). Poor for anything transactional, auditable, or security-relevant.
  • Anti-fit: secrets/credentials (plaintext in DB), authorization gating, pricing or billing thresholds, anything needing an audit trail or approval workflow. Do not put those here.
  • The model-scoped feature is the only non-commodity part. Treat it as unproven until you've seen the migration's indexes. A polymorphic settings table without a composite index on (model_type, model_id, key) is a query-storm waiting to happen at scale.

Integration feasibility. High on the technical axis, moderate on the lifecycle axis.

Factor Assessment
License MIT — clean, no legal review needed
Dependencies Laravel/Illuminate only; no external services, no daemons
Install surface Composer + one migration + optional config publish
Data footprint One table; reversible with a rollback migration
Exit cost Low — read the source, wrap behind your own interface, replace later
Version currency Last release 2022-12-14; Laravel 11/12 support is unverified
Community 7 stars — effectively no third-party review, no CVE eyeballs, no issue triage

Technical risk (ranked).

  1. Abandonment / framework drift. A Dec-2022 release predates Laravel 11's provider and skeleton changes. composer.json constraints will tell you instantly whether it installs on your target version; the real question is whether it works on it. No maintainer cadence means no fix if it doesn't.
  2. Silent misconfiguration. The dominant failure mode of settings packages is a missing key returning null instead of your intended default, or a driver/config fallback that resolves to something you didn't choose. Requires an explicit boot-time assertion test.
  3. Cache coherence. Unknown, unverified: does set() invalidate the cache? Across queue workers, multiple app servers, and Octane? If the cache is process-local or per-instance, you get split-brain settings in production — the worst kind of bug because it's intermittent and environment-dependent.
  4. Type coercion. "Support for multiple value types" is only as good as the round-trip. Booleans stored as "false" are truthy in PHP; arrays stored via serialize() are unreadable by other tooling. Pin this down with a round-trip test per type.
  5. Unbounded global mutable state. Any package like this degrades into an untyped $_GLOBALS unless governed. That's an organisational risk you're importing, not a package defect — but it lands on your plate.
  6. Security surface. Rows are editable by anyone with DB or artisan tinker access. If a setting controls behaviour (rate limits, feature exposure, outbound endpoints), that's a privilege-escalation path with no audit trail.

Key questions to resolve before committing.

  • Does composer.json allow the Laravel and PHP versions we actually run? Test on the newest supported, not the oldest.
  • What is the exact schema — column types, indexes, uniqueness constraints — for both the global and model-scoped tables?
  • How is cache invalidated on write, and is it shared across processes? Does it survive config:cache?
  • What does get() return for a missing key, and can we inject a default without ambiguity with a stored null?
  • Are model-scoped settings eager-loadable, or does each access hit the DB?
  • Is there any published changelog or upgrade guide at all? (The assessment notes suggest not — treat empty release notes as a risk signal.)
  • Who owns this internally when the upstream repo goes quiet? (It already is.)

Integration Approach

Stack fit and the alternative. For a Laravel monolith or a small service, this fits without ceremony. But be honest in the comparison: spatie/laravel-settings is the de facto standard — maintained, typed settings classes, strong static analysis story — at the cost of more ceremony and a per-class codegen pattern. pharaonic/laravel-settings wins only if you want a loose key/value bag with zero class scaffolding. If your team wants typed, greppable, refactor-safe settings, this is the wrong tool and the decision will be regretted in twelve months when the settings table has 400 undocumented keys.

Choose this package when: the settings are few, operational, and genuinely dynamic. Otherwise choose a typed alternative or a JSON column on your own model.

Migration path (adopt).

  1. Pin, don't float. composer require pharaonic/laravel-settings:<exact> in a branch. No caret range until you've verified the constraint resolves on your Laravel version.
  2. Publish into version control. vendor:publish the config and migration; commit both. The published config is the real documentation for a package with thin docs.
  3. Run the migration as a distinct deploy step, not inside the app boot or an auto-migrate hook. Make sure the rollback (down()) is safe to run and that the migration filename won't collide with existing settings tables.
  4. Wrap immediately. Define App\Contracts\SettingsRepository with get/set/forget and a typed accessor layer on top. Bind the package facade behind it. No Facade calls in services, jobs, or listeners — delivery layer only. This is the seam that makes the exit cheap and testing clean.
  5. Register a key registry. A single class or config file enumerating every valid key with its type and default. Reject unknown keys in the adapter (throw in non-production, log in production). This is the governance control that prevents key sprawl and is the highest-leverage thing you will do.
  6. Decide the caching story yourself. If the package's cache semantics are unclear, disable its cache and put your own Cache::remember in the adapter with explicit invalidation on set(). Own the invalidation; don't inherit it.
  7. Seed defaults idempotently via a seeder or artisan command so a fresh environment and a recovered environment converge on the same state.

Compatibility work.

  • Run the package's own test suite (if any) plus a minimal read/write smoke test against MySQL, PostgreSQL, and SQLite if you support all three. JSON vs. serialized columns behave differently across drivers.
  • Verify behaviour under php artisan config:cache and under Octane if you use it — check the provider for singleton() bindings holding request state and re-register as scoped() in your own provider if so.
  • Add a boot test asserting the resolved cache store and driver, so a missing config key fails loudly in CI instead of silently in production.

Sequencing (six weeks, part-time).

Phase Work Exit criteria
1 (wk 1) Spike: install pinned, publish, migration, read-only path in a throwaway branch Round-trip test passes for every supported type
2 (wk 2) Adapter + contract + key registry + boot assertions Domain code compiles with zero facade references
3 (wk 3) Migrate tier 1 values (non-critical operational flags) from env/hardcoded Feature-flagged; flag defaults to old source of truth
4 (wk 4–5) Run shadow: write to both, read from old, log divergence One clean release cycle, zero divergence
5 (wk 6) Flip flag, document runbook, publish exit plan On-call can restore previous behaviour from a single commit

Do not, in v1: use the model-scoped settings feature, put secrets in the table, or make the write path reachable from a user-facing form without authorization and validation in front of it.

Operational Impact

Maintenance. The package is effectively frozen. Budget for owning it rather than depending on it: assume you will fork or reimplement within 18–24 months, most likely triggered by a Laravel major upgrade. Reimplementation cost is a day or two of engineering — that's the number that makes this decision cheap. Do not, however, let "it's only 150 lines" become an excuse to skip the wrapper; the wrapper is what makes the reimplementation a day instead of a sprint.

Support. No vendor, no maintainer cadence, no community. Name a single internal owner in the ADR. If nobody volunteers, that's your answer on adoption.

Scaling characteristics.

  • Read amplification: settings are read on nearly every request. Without a shared cache you will add a query per request, and with model-scoped settings you can add one per model per render. Mandatory: shared cache store (Redis/Memcached), not array or file, in any multi-instance deployment.
  • Write contention: writes are rare by design but should not happen inside request paths that run concurrently. Route writes through an artisan command or admin endpoint, never through application code triggered by user traffic.
  • Table growth: global settings stay tiny; model-scoped settings scale with your domain cardinality. A hundred thousand models × five keys is a half-million rows — fine with correct indexes, pathological without them.
  • Cache stampede: a deploy that clears cache while settings are read on every request produces a thundering herd against a single small table. Warm the cache in the deploy hook (octane:warm or a boot-artisan command) or accept the cold-start burst knowingly.

Failure modes to instrument.

Failure Symptom Mitigation
Missing key → null Feature behaves as disabled; not obviously a bug Registry with required keys; throw in non-prod; assert on boot
Stale cache after write Setting changed but behaviour doesn't Own the invalidation; log every set() with old/new
Cross-worker inconsistency Intermittent, environment-dependent behaviour Shared cache store; verify in a 2-worker staging test
Type drift Boolean "false" evaluates truthy Typed accessors only; no raw get() outside the adapter
Provider/version mismatch after upgrade Hard failure at boot — actually the good case Pin exact versions; upgrade in branch; artisan about check
Octane state leakage Values bleed between requests scoped() binding in your provider; add to Octane flush list
Plaintext secrets in DB Credential exposure in backups/reads Policy: secrets stay in env/secret manager, always

Ramp-up. Very low developer friction — an engineer can use it in under an hour. That's also the risk: the API is simple enough to be misused casually, and the cost lands on operations. Counter it with three artefacts: (1) the key registry as the single source of truth, (2) a short ADR stating what this package is not for (secrets, authz, audit-sensitive values), and (3) a code-review rule that raw facade calls are rejected outside the delivery layer.

Overall posture. Conditional, low-stakes adoption. The blast radius is small, the exit cost is low, and the capability is commodity — so the decision is defensible even with a stale dependency. Gate it on three things: it installs and passes a round-trip test on your target Laravel version, the wrapper and key registry exist before any domain code touches it, and someone's name is on the ADR as owner. If any of those three fails, write the 150 lines yourself and skip the dependency entirely.

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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json