cendekia/nova-setting-tool
A Laravel Nova tool for managing application settings directly from your admin panel. Store and edit key/value configuration through a clean Nova interface, so values can be changed without touching code or redeploying. Simple to install and customize.
Install and register
composer require cendekia/nova-setting-tool
Publish and run the package's migration (the settings are persisted in the database, so this step is not optional):
php artisan vendor:publish --provider="Cendekia\NovaSettingTool\NovaSettingToolServiceProvider"
php artisan migrate
Register the tool in app/Providers/NovaServiceProvider.php inside the tools() method so it shows up in the Nova sidebar:
use Cendekia\NovaSettingTool\NovaSettingTool;
public function tools()
{
return [
new NovaSettingTool(),
// ...
];
}
Where to look first
config/nova-setting-tool.php (after publishing) — the list of editable settings keys, labels, and defaults usually lives here.settings table migration — confirms whether values are stored as key/value rows or dedicated columns.resources/js — the fastest way to see which fields are actually rendered and how they are saved.First use case
Log into /nova, open the new "Settings" item in the sidebar, set the app title and copyright line, save, and refresh. Then wire the value into your layout so it stops being a static config('app.name'):
<title>{{ setting('app_title', config('app.name')) }}</title>
<footer>© {{ setting('copyright_text') }}</footer>
If the package ships a global helper (commonly setting()), that is your primary read API; otherwise use the model directly (Cendekia\NovaSettingTool\Models\Setting::value('app_title')). Confirm the exact helper name in the package's helpers.php or README before spreading it across views.
Read-through helper with sensible fallbacks. Treat the helper as the only read path and always pass a default:
$name = setting('app_title', config('app.name'));
This keeps the app bootable before the migration has run (fresh clones, CI, other developers) and makes the package an override layer on top of config/ rather than a hard dependency.
Override framework config at boot. The most valuable pattern is pulling the stored title back into Laravel's config so Nova, mail templates, and config('app.name') consumers all pick it up. Do this in a service provider boot():
public function boot()
{
if (Schema::hasTable('settings')) {
config(['app.name' => setting('app_title', config('app.name'))]);
}
}
Guard on the table existing — this code runs on composer install, in queue workers, and on every route, including ones served before migrations.
Version display. The app_version setting is best used as a manual release marker shown in your layout and Nova footer, kept in sync by whoever cuts the release. If you already tag releases, prefer reading from a build artifact and store the setting only as an override so it cannot silently drift from the deployed code.
Caching. Settings are read on every page render. Wrap the reads in a cached accessor rather than hitting the table in the layout:
$settings = Cache::rememberForever('nova-settings', fn () => Setting::pluck('value', 'key'));
Then flush that key from a model observer on the Setting model (or in the tool's save path). Without a flush hook you get stale titles after editing, which is the number one "the package is broken" report.
Multi-tenant or per-context values. If you need tenant-specific branding, do not fork the package. Keep the package's table for global defaults and layer your own scoped table keyed by tenant; resolve setting() first, then fall back to globals. Mixing scopes into the shipped table means fighting the tool's UI.
Access control. The tool is visible to every Nova user by default. Restrict editing to admins:
public function tools()
{
return $this->canSeeSettings() ? [new NovaSettingTool()] : [];
}
protected function canSeeSettings(): bool
{
return Nova::whenServing(fn ($request) => $request->user()?->isAdmin() ?? false);
}
Alternatively gate the underlying resource with a policy so API-level edits are blocked, not just the sidebar link.
vendor:publish --provider=... dumps everything, including assets you may not want to own. Prefer --tag=nova-setting-tool-config / --tag=nova-setting-tool-migrations if the package defines them, so upgrades don't silently overwrite your customized config.config(['app.name' => ...]) override in the same deploy, run php artisan migrate before the app takes traffic, or guard with Schema::hasTable() as shown above.composer update, run php artisan nova:publish and npm run build (or dev) — a stale public/vendor/nova build is the usual cause of a blank settings page or a save button that does nothing.php artisan config:cache also freezes any config(['app.name' => ...]) override applied at boot — the order of provider booting versus cached config matters."" rather than null, so setting('x', 'default') returns the empty string and your fallback never fires. Normalize with setting('x') ?: 'default'..env/a secrets manager, not in this tool. The "basic admin panel settings" scope is branding, not configuration management.Setting model to flush caches and log changes, plus a custom Nova field if you need richer inputs (colors, images) than the shipped form provides. Avoid editing vendor/ — publish the config and asset tags so you own the files you change.php artisan view:clear).composer.json, and keep the read path behind a single helper/facade of your own so swapping the package out later is a one-file change.How can I help you explore Laravel packages today?