queents/vilt
queents/vilt is a Laravel starter kit bundling Vue 3, Inertia and Tailwind into a ready-to-use VILT stack, with authentication, an admin panel scaffold, and reusable UI components to speed up building modern full-stack apps.
queents/vilt is the VILT-stack (Vue + Inertia + Laravel + Tailwind) scaffolding layer from the Queents/Tomato ecosystem. It gives you generated Inertia pages, Vue components, and admin-oriented CRUD flows instead of hand-wiring the same boilerplate for every resource.
composer require queents/vilt
Then discover what the package actually registered before assuming command names — this is the fastest way to orient yourself:
php artisan list | grep vilt
php artisan vendor:publish --provider="Queents\Vilt\ViltServiceProvider"
Look at these three places first, in order:
config/vilt.php (after publishing) — feature toggles, route prefix, middleware, layout/component paths.routes/ file — confirms the URI prefix and which middleware group your generated screens land in (web only vs. auth/admin guard).resources/js/Pages/ in your app — where generated Inertia page components are expected to resolve.First use case: scaffold one throwaway resource end-to-end (e.g. a Post CRUD), load it in the browser, and only then delete it. You learn the generator's output shape, the prop contract between controller and page, and whether your Vite/Tailwind build picks up the package's components — all in about ten minutes.
Generator-first, then hand-edit. Use the package's generators to emit the controller/page/component trio, commit that output untouched, then customize in a second commit. Keeping the two diffs separate is what makes future package upgrades reviewable.
Treat generated Inertia pages as a starting contract. The controller returns props; the Vue page consumes them. When you extend a screen, prefer adding props in your own controller over mutating the page's internal state — it keeps the contract visible and testable.
Compose alongside your own routes. Register VILT screens inside your existing admin route group rather than letting the package own the whole admin surface:
Route::middleware(['web', 'auth', 'admin'])
->prefix('admin')
->group(base_path('routes/vilt.php'));
This keeps guard, prefix, and middleware decisions in your application's hands.
Shared props belong in HandleInertiaRequests. Auth user, flash messages, and menu state should flow through Inertia's shared props, not be duplicated into every generated controller. Generated pages will assume some of these exist — centralizing them prevents per-page patches.
Translations are now an explicit choice (v1.0.6). Prior releases pulled in the translation-loader dependency transitively; v1.0.6 removed it. If your generated screens use DB-backed translations, install the loader yourself:
composer require spatie/laravel-translation-loader
If you don't need it, do nothing — the removal just trims your dependency graph.
Asset pipeline. Ensure vite.config.js inputs and tailwind.config.js content globs include the package's Vue/Blade paths. If Tailwind classes from package components silently don't apply, this is almost always the cause.
v1.0.6 is a dependency-removal release — audit before upgrading. The translation-loader package is no longer installed for you. Before bumping:
composer why spatie/laravel-translation-loader # confirm whether you actually depend on it
composer update queents/vilt --with-dependencies
php artisan optimize:clear
If composer why shows it was only present as a transitive dependency of vilt, add it to your own require block or accept the loss. Symptom of missing it: translation-editing screens 500 with a class-not-found or missing-table error. Note the loader's own migration also needs publishing/running if you add it back.
Pin the version. A 1.0.x line that ships dependency changes in patch releases is a line you should pin exactly ("queents/vilt": "1.0.6") and upgrade deliberately, reading the changelog each time.
Never --force a vendor publish over a customized tree. Run vendor:publish without --force, then diff. Config and stub files are where your local modifications live, and they're the first thing an upgrade will clobber.
Customize via published stubs, not vendor edits. If the generators don't emit what you want, publish the stubs and edit those. Files under vendor/ evaporate on the next composer update.
Page resolution is case- and path-sensitive. Inertia resolves Inertia::render('Posts/Index') against your configured page path. Mismatched casing works on macOS and breaks on Linux CI — a classic "works locally, 500s in prod" failure.
Debugging checklist when a screen renders blank: confirm the route exists (php artisan route:list --path=admin), confirm the browser response includes a data-page attribute on the root div (proves Inertia rendered server-side), then check the browser console for a missing chunk. Blank-with-no-console-error usually means a Vite entry wasn't built after a component was added.
Extension points worth knowing: published config (feature toggles), published stubs (generator output), and published Vue components (visual overrides). Prefer them in that order — config survives upgrades best, component overrides worst.
Add one smoke test. A single feature test asserting a generated index route returns 200 with the correct Inertia component name catches the majority of upgrade breakage before it reaches a browser.
How can I help you explore Laravel packages today?