inani/laravel-nova-configuration
Manage your Laravel app's configuration from inside Nova. Edit config values through a dedicated settings screen backed by database storage, with caching and grouped settings, so you can change options without redeploying code.
The package swaps .env/config/ edits for a database-backed settings screen inside Nova, so non-technical clients can change values (support email, feature toggles, API keys, copy text) without a deploy.
Install into a project pinned to the Nova version the package supports (2019-era: Nova 2.x / Laravel 5.8):
composer require inani/laravel-nova-configuration
Publish the config file and migration, then migrate:
php artisan vendor:publish --provider="Inani\NovaConfiguration\ToolServiceProvider"
php artisan migrate
Register the tool in app/Providers/NovaServiceProvider.php:
public function tools()
{
return [
new \Inani\NovaConfiguration\NovaConfiguration,
];
}
Open config/nova-configuration.php (the first place to look) — this is where you declare the inputs the client will see. Define your first field, e.g. a "Support email" text input, then log into Nova and edit it.
First use case: take a value you currently read from env() — say config('app.support_email') — move it into the configuration screen, and read it back through the package's accessor/Config model instead.
Before committing, verify the exact accessor signature, table name, and config schema against the published files; the README is thin and the package predates several Laravel/Nova API changes.
Group fields by intent. Model the config screen the way the client thinks — General, Mail, Integrations, Feature Flags — rather than mirroring your .env keys one-to-one. Each group becomes a section in the tool; keep it short enough that a non-developer can scan it.
Read through a single accessor. Wrap the package's lookup in your own helper or a small Settings service and use that everywhere (controllers, Blade, Nova fields, queued jobs):
// app/Support/Settings.php
class Settings
{
public static function get(string $key, $default = null)
{
return Cache::rememberForever("settings.{$key}", function () use ($key, $default) {
return \Inani\NovaConfiguration\Models\Config::where('key', $key)->value('value') ?? $default;
});
}
}
This gives you one seam to swap the package out later and one place to add caching.
Fallback to config()/env(). Treat the DB as an override layer, not the only source. Settings::get('mail.from', config('mail.from.address')) keeps fresh environments, CI, and new developer machines working before anyone has touched the Nova screen.
Feature flags. Booleans work well here: a checkbox in the tool, Settings::get('features.beta_checkout', false) in a service provider or middleware. Because the value lives in the DB, you can toggle per environment (staging DB vs. prod DB) without touching code.
Cache with explicit invalidation. A DB read per settings lookup is wasteful. Cache the whole resolved config array once per request, or use Cache::rememberForever with a key you flush from a model observer on save. If you already run config:cache in deploy, remember it has no effect on DB-backed values — this is a separate cache layer.
Validate on write. The tool is a UI over your database; add validation rules in the config where supported (email, url, integer), otherwise a client will happily save "yes" into a boolean field. Where the package doesn't expose rules, cast and sanitize on read.
Seeding defaults. Ship a seeder that inserts the keys your app expects with sensible defaults. This makes first boot deterministic and documents the contract between code and the configuration screen.
Authorization. Restrict who sees the tool via Nova's Gate/Nova::auth or the tool's canSee behavior — not every Nova user should be able to change SMTP credentials. In multi-tenant setups, scope by team if the package's schema allows; otherwise run one instance per tenant.
Use it for content, not architecture. Great fits: support contact details, social links, announcement banners, throttle limits, third-party API base URLs, on/off switches. Poor fits: anything that must be identical across all app servers and change atomically with a deploy (queue names, cache prefixes, encryption keys).
ToolServiceProvider namespace may need updating. Pin Nova and Laravel versions in composer.json before adding it, and check composer why-not if resolution fails. With zero dependents, there's no community pressure to keep it current — budget time to vendor/fork it.encrypted cast or an EncryptsAttributes trait on the model). Prefer keeping secrets in .env and exposing only non-sensitive knobs in the UI.filter_var($v, FILTER_VALIDATE_BOOLEAN)), JSON (json_decode), and integers explicitly at the read boundary or you'll ship "false" being truthy.saved/deleted observer to flush your settings cache key, and verify it by changing a value and hitting the app without restarting anything.config:cache confusion. Developers often expect php artisan config:cache to pick up DB changes — it won't. Conversely, during local debugging, a cached settings key will mask a fresh DB write; Cache::flush() or use a tagged store in dev.configurations/settings table, check the published migration's table name and rename it (or the migration will fail or silently conflict). Publish tags explicitly rather than relying on the provider default.NovaServiceProvider::tools()? Does the Gate allow the current user? Does the migration exist and run? Is the field declared in config/nova-configuration.php? Is your read path hitting the right model/table? Work down that list before assuming the package is broken.app/ and resources/ overrides so a composer update (or a future fork swap) doesn't blow them away.Settings helper and keep an env() fallback, so migrating to spatie/laravel-settings, a custom settings model, or Nova's built-in fields is a one-file change rather than a refactor.How can I help you explore Laravel packages today?