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

Nova Settings Laravel Package

outl1ne/nova-settings

outl1ne/nova-settings is a Laravel Nova package for managing application settings directly from the Nova admin panel. Define settings pages with custom fields and groups, persist values to the database, and keep configuration editable without code changes.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and publish its migration/config:

composer require outl1ne/nova-settings
php artisan vendor:publish --provider="Outl1ne\NovaSettings\NovaSettingsServiceProvider"
php artisan migrate

Register the tool in app/Providers/NovaServiceProvider.php:

public function tools(): array
{
    return [
        \Outl1ne\NovaSettings\NovaSettings::make(),
    ];
}

Register your first fields in the same provider's boot() method. This is the file you will live in day-to-day:

use Outl1ne\NovaSettings\NovaSettings;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Textarea;

public function boot(): void
{
    parent::boot();

    NovaSettings::addSettingsFields([
        Text::make('Site name', 'site_name')->rules('required'),
        Textarea::make('Footer text', 'footer_text'),
    ]);
}

Read values anywhere in your app with the helper:

$siteName = nova_get_setting('site_name', config('app.name'));
$footer   = nova_get_setting('footer_text');

// Everything at once
$settings = nova_get_settings();

First practical use case: move hard-coded marketing copy, contact emails, social URLs, API keys for non-sensitive integrations, and simple feature flags out of Blade/controllers and into a Nova-editable page. Open /nova/settings as an admin and confirm the values persist.

Implementation Patterns

Group related fields with Panels. The settings page is a single form; use Laravel\Nova\Panel to keep it navigable as it grows.

NovaSettings::addSettingsFields([
    Panel::make('General', [
        Text::make('Site name', 'site_name'),
        Image::make('Logo', 'logo'),
    ]),
    Panel::make('Contact', [
        Text::make('Support email', 'support_email'),
        Text::make('Phone', 'support_phone'),
    ]),
]);

Keep field definitions out of the Nova tool class. Put them in a dedicated service provider (e.g. SettingsServiceProvider) or a config/settings.php schema that your provider loops over. This keeps NovaServiceProvider from becoming a dumping ground and makes it easy to conditionally register fields per environment or per tenant.

Always pass defaults when reading. A setting that has never been saved returns null; treat the getter default as the source of truth for fresh installs.

$perPage = (int) nova_get_setting('per_page', 25);
$flags   = (array) nova_get_setting('feature_flags', []);

Store structured data deliberately. KeyValue, Boolean, Select, and Date fields all serialize back through the getter, but the returned PHP type depends on how Nova cast the input. Cast explicitly at the read site ((bool), (int), json_decode) rather than assuming. For arrays of links or nav items, KeyValue is usually more maintainable than multiple flat fields.

Prefer Markdown fields for long-form copy. Since 6.0.2 the settings form renders a live preview for Laravel\Nova\Fields\Markdown fields, so editors can validate headings, links, and lists without leaving /nova/settings. Use it for footer copy, announcement banners, and legal blurbs instead of a raw Textarea:

Markdown::make('Footer text', 'footer_text')
    ->help('Markdown supported — preview renders as you type.'),

The stored value is the raw Markdown string, so render it at the read site (see gotchas below).

Use settings as configuration inputs, not business data. Good candidates: feature toggles, default pagination, contact endpoints, allowed file types, announcement banners. Bad candidates: records that need relationships, audit trails, or per-user overrides — those belong in their own tables/resources.

Write programmatically sparingly. For seeders, onboarding flows, or admin actions outside Nova, set values through the facade/model rather than inserting rows by hand. This keeps any package-level casting/caching consistent:

NovaSettings::setSettings([
    'site_name'    => 'Acme',
    'support_email'=> '[email protected]',
]);

Use settings to seed Nova resource defaults. A common pattern is to read a setting inside a resource's fields() or default callback so admins can change global defaults without a deploy:

Text::make('Locale')->default(fn () => nova_get_setting('default_locale', 'en')),

Gate the tool. By default any Nova user can open the settings page. Restrict it in NovaServiceProvider (e.g. NovaSettings::make()->canSee(fn ($request) => $request->user()->isAdmin())) or via a policy if you have non-admin Nova users. Settings often contain integration credentials — treat the page as admin-only.

Resolve files/images through storage. Image/File fields store a disk path. When rendering, resolve it with Storage::disk(...)->url($path) rather than concatenating URLs, especially if you use S3 or a non-default disk.

Cache at the call site if you read hot settings frequently. The package reads from the database. If a layout partial calls nova_get_setting() repeatedly, wrap it in a small cached helper (Cache::remember('settings.site_name', ...)) and clear on save, or memoize per-request in a singleton.

Gotchas and Tips

  • Field registration is boot-time, not tool-time. addSettingsFields() must run on every request that renders or saves the settings page. Registering inside the tool class or a controller will produce an empty form or lose fields on save.
  • Field names are global keys. Two fields with the same ->attribute() will collide — last registration wins. Prefix with a domain (billing_, seo_) to avoid accidental overwrites across providers.
  • Renaming a field orphans data. Changing the attribute leaves the old row in nova_settings and the new field starts empty. Write a small migration or updateOrInsert to move values when renaming.
  • nova_get_setting() and the table must exist. Do not call the helper from an early service provider, config file, or a migration that runs before the package migration — you will hit "table not found". Guard or defer to after boot.
  • Booleans and empty strings are easy to confuse. An unchecked Boolean may save false or null depending on Nova version; a Text field saved empty may be '' rather than null. Normalize in your accessor.
  • Markdown preview is edit-time only. The 6.0.2 preview renders inside the Nova form; the getter still hands you the raw Markdown source. Render it yourself with Str::markdown($value) (or a CommonMark parser) and sanitize HTML before echoing it into Blade with {!! !!} — untrusted editor input otherwise becomes stored XSS. Never assume the preview implies sanitization.
  • Publish tags vary by version. If vendor:publish produces nothing, list tags with php artisan vendor:publish and check the package's config/nova-settings.php for the actual table name and publish tags instead of guessing.
  • Validation lives on the Nova fields. Add ->rules() to fields you care about (emails, URLs, required values). Invalid settings saved silently become production bugs; the form is your only guardrail.
  • Nova version compatibility. This package tracks Nova 4/5. After a Nova major upgrade, run the settings page manually — field APIs and tool registration occasionally shift, and a broken form is not caught by PHPUnit unless you test the tool endpoint. The same applies to the Markdown preview added in 6.0.2: verify it renders after upgrading Nova, since it depends on Nova's field component registration.
  • Authorization is your responsibility. There's no built-in per-field permission. If only some admins should edit billing settings, split into separate tools or hide fields with ->canSee().
  • Debugging checklist: confirm the provider is registered in config/app.php, confirm the migration ran (nova_settings table exists and has rows), confirm the field attribute matches the key you pass to nova_get_setting(), and check storage/logs/laravel.log for Nova field exceptions during save.
  • Extension point: the settings model is a normal Eloquent model. If you need audit history, add an observer on save rather than forking the package; if you need custom pages, wrap the tool with your own Nova tool and reuse the facade for storage.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle