norman-huth/nova-basic-package
A basic starter package for Laravel Nova that gives developers a simple foundation for building custom Nova tools, cards, and packages, with ready-made structure and conventions to speed up development.
norman-huth/nova-basic-package (published on GitHub as Muetze42/nova-basic-package) is a skeleton / scaffold for building a custom Laravel Nova package — not a runtime library you require into an existing app. Its value is time saved when you need to ship your own Nova tool, card, field, or resource group with the same conventions Norman Huth uses across his Nova ecosystem (ServiceProvider, package config, Vite/webpack build, tests, CI).
Treat it as a reference implementation and template, not a dependency. Read it, fork it, rename it, and vendor the structure into your own repo.
Changed in 1.2.7: the package is no longer frozen at 1.0.0 — it has moved through 1.1.x to 1.2.7. That's a semver patch line off a 1.x base, so nothing should be breaking, but it also means the "archived, never updated" assumption in the prior assessment no longer holds and the scaffold has drifted from what you may have forked. Before you copy anything, open the changelog link from the release (compare/1.0.0...1.2.7) and read the actual diff — the release notes themselves are auto-generated and contain no description.
Minimal steps to get going:
composer require it. Instead, on GitHub, use the "Use this template" button (or git clone + delete .git) so you start from a clean history. If you already forked from 1.0.0, clone 1.2.7 fresh and diff rather than merging — renames make merges painful.1.0.0...1.2.7 comparison first. Note which files changed (provider, package.json, Vite config, CI matrix) — those are exactly the files you are about to customise, so knowing what upstream touched tells you what to re-check later.composer.json (name, namespace/PSR-4 autoload)package.jsonsrc/NovaBasicPackageServiceProvider.php (or equivalent) — class name, $name, $description, and the boot()/register() bodiesconfig/nova-basic-package.phpresources/js/* and resources/sass/* entry pointscomposer install && npm install && npm run dev inside the package directory to confirm the toolchain builds before you write any feature code. Do this on the 1.2.7 tag specifically — build config is the most likely thing to have changed across the 1.x line.repositories path entry, then verify the tool shows up in Nova's sidebar.First use case: create a Nova card or tool that consumes your app's API. The scaffold gives you the Vue entry, the Nova Tool/Card base class, and the routes/api.php wiring Nova expects, which is usually where people lose hours.
Fork-and-rename workflow. The intended pattern is "template repo," not "installed package." Keep a private fork named acme/nova-your-tool. Because upstream now has an active 1.x line, decide explicitly how you relate to it:
1.2.7, rename immediately, and never look back. Record the source tag in your README.merge upstream into your renamed fork — the find/replace rename guarantees conflicts.Pin your fork to a specific commit in your app's composer.json using a VCS repository entry:
"repositories": [
{ "type": "vcs", "url": "[email protected]:acme/nova-your-tool.git" }
]
Local development loop. During development, symlink the package into vendor/:
ln -s /path/to/nova-your-tool vendor/acme/nova-your-tool
Then run npm run watch inside the package and php artisan serve in the app. Nova tools hot-reload reasonably well if the mix-manifest.json (or Vite manifest, depending on the scaffold version) resolves; expect to hard-refresh Nova after Vue edits.
Service provider conventions. The scaffold typically wires up:
boot() — publishable config, translations, migrations, assets; merges Nova routes under the nova-api prefix.register() — config merge, container bindings.NovaBasicPackage facade or helper class for shared logic.Keep your own feature code in src/ alongside the provider and mirror the naming (Acme\NovaYourTool\YourTool). The scaffold's naming is templated; a global find/replace of NovaBasicPackage → YourTool (case-sensitive across PascalCase, kebab-case, snake_case) catches 95% of it. Grep for nova-basic-package and Muetze42 afterward to catch the remainder in README, LICENSE, composer metadata, and asset paths.
Asset build. The default webpack/Vite config is opinionated — Tailwind + Nova's design tokens are usually pre-wired. If you only need a simple card, this is heavier than necessary; strip the Tailwind config and reduce resources/js/tool.js to the minimum Nova.booting(app => …) registration. If you need a full tool with routing, keep the scaffold's Tool.vue layout and sidebar registration in the provider:
Nova::script('your-tool', __DIR__.'/../dist/js/tool.js');
Nova::style('your-tool', __DIR__.'/../dist/css/tool.css');
Testing integration. The scaffold ships a PHPUnit setup and a .github/workflows pipeline. Copy the workflow verbatim into your fork and update the matrix. The 1.2.7 release is the best available signal of what the author currently supports — check the workflow file's PHP/Laravel/Nova matrix at that tag rather than trusting the prose in the README, then verify against your Nova major.
Config publishing pattern. Follow the scaffold's mergeConfigFrom + publishes pair so consumers can override defaults:
$this->mergeConfigFrom(__DIR__.'/../config/your-tool.php', 'your-tool');
$this->publishes([__DIR__.'/../config/your-tool.php' => config_path('your-tool.php')], 'your-tool-config');
Diff-driven upgrade habit. When a 1.2.x release lands, git diff 1.2.6 1.2.7 -- src config resources/js package.json in your un-renamed reference clone. Patch-level changes in a scaffold are usually dependency bumps and CI tweaks — cheap to cherry-pick by hand into your renamed fork, and it's the only realistic way to stay current without redoing the rename.
1.2.7 disproves that. Re-check the repo's archived banner / release feed each time rather than trusting any snapshot assessment (including this one). What has not changed: zero stars, zero dependents, so still no third-party battle-testing.1.2.7 ships as an auto-generated changelog link only. Do not assume "patch bump = irrelevant" for a scaffold — a one-line change to the Vite config or the CI matrix is exactly the kind of thing you forked this repo to get right. Read the diff.1.0.0 → 1.2.7 means your fork is behind. If you forked from the old 1.0.0 template, your CI matrix and JS build are now two minor versions behind upstream's opinions. Compare package.json, the Vite/webpack config, and .github/workflows specifically — those are the highest-churn files in a scaffold and the ones most likely to have drifted from your Nova version.composer require norman-huth/nova-basic-package and are surprised when nothing useful appears in the Nova menu. The package is a template; nothing registers a tool at runtime unless you fork it and supply your own Tool class. A new 1.2.7 release does not change this.1.2.7 into an already-renamed fork re-introduces the default names — grep after every manual port.package.json may pin an old Vue 2 build while your Nova 5 app expects Vue 3. Check npm ls vue and align resources/js/tool.js with the Nova version you actually run. If 1.2.x bumped Vue or Vite, that's a change you probably want, but it may also force a Node version bump in CI.Route::middleware(['nova'])->prefix('nova-api')->group(...) calls in the scaffold assume Nova's auth middleware alias is registered. If your app customized Nova's middleware stack, your tool's endpoints will 401 silently — check storage/logs/laravel.log and add explicit ->middleware('auth') to debug.composer.json scripts. The scaffold may include scripts.post-autoload-dump for vendor:publish, which fires on every composer install. If you vendor the code into an app rather than a package, those hooks are noise — strip them.mergeConfigFrom runs on register(), but if a consumer has published config/your-tool.php and then runs php artisan config:cache before updating it, old values persist. Document config:clear in your README. Watch for this especially when porting a 1.2.x config default into a fork whose published config was generated from 1.0.0 — the published file wins over the merged default.config/, resources/lang/, and the provider's boot() publishes array — even if you don't use them today, downstream consumers of your fork will want to override strings and settings without editing vendor code.database/migrations/stubs/ directory, those are meant to be copied and renamed per-model, not published wholesale. Running vendor:publish --tag=migrations on them creates duplicated tables if you do it twice. Re-copying stubs from 1.2.7 after you've written migrations is a common source of duplicate-table errors in local setups.Bottom line: the 1.2.7 release is the single most useful piece of news about this package — the template is being maintained again (or at least bumped), so read the changelog and diff it against your fork before deciding you're current. Adopt the structure (provider layout, asset pipeline, config merge, CI workflow), not the package, and budget an hour to reconcile it against your Nova version.
How can I help you explore Laravel packages today?