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

Laravel Package Tools Laravel Package

spatie/laravel-package-tools

PackageServiceProvider base class for Laravel packages that simplifies registering config files, migrations, views, translations, routes, commands, assets, and view components, with publishable resources and a configurable install command.

View on GitHub
Deep Wiki
Context7

Getting Started

spatie/laravel-package-tools is a base PackageServiceProvider that turns package boilerplate into a declarative configurePackage() method. Instead of hand-writing mergeConfigFrom, loadViewsFrom, loadMigrationsFrom, publishes, route loading, and command registration, you describe the package once and the provider wires it up.

Minimal path:

  1. For a new package, start from spatie/package-skeleton-laravel; it already matches the expected directory structure. For an existing package, require spatie/laravel-package-tools and extend the provider.
  2. Create src/YourPackageServiceProvider.php extending Spatie\LaravelPackageTools\PackageServiceProvider, implement configurePackage(Package $package): void, and call $package->name('your-package-name'). The name is mandatory.
  3. Put files where the package expects them: config/, database/migrations/, routes/, resources/views/, resources/lang/, resources/dist/, src/Commands/, src/Components/.
  4. First use case: register a config file, a migration stub, and a command.
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;

class YourPackageServiceProvider extends PackageServiceProvider
{
    public function configurePackage(Package $package): void
    {
        $package
            ->name('your-package-name')
            ->hasConfigFile()
            ->hasMigration('create_your_package_tables')
            ->hasCommand(YourCoolPackageCommand::class);
    }
}

Then in a host app, publish what you need:

php artisan vendor:publish --tag=your-package-name-config
php artisan vendor:publish --tag=your-package-name-migrations

Look first at the README sections Directory Structure, Config Files, Working with migrations, and Creating an Install Command. Then inspect Spatie\LaravelPackageTools\Package for exact method signatures. The package skeleton is the fastest reference implementation.

Implementation Patterns

  • Treat configurePackage() as the package manifest. Chain capabilities: hasConfigFile(), hasViews(), hasTranslations(), hasAssets(), hasRoute('web'), hasMigrations([...]), hasCommands([...]), hasViewComponents('prefix', Alert::class), hasViewComposer('*', MyViewComposer::class), sharesDataWithAllViews('downloads', 3), publishesServiceProvider('MyProviderName'), hasInertiaComponents(). Use plural methods for arrays and singular methods repeatedly otherwise.

  • Config: hasConfigFile() merges and publishes config/<short-name>.php. Multiple files: hasConfigFile(['my-config', 'another-config']). Read values with config('your-package-name.key'). Publish tag: <short-name>-config.

  • Migrations: for publishable stubs, place create_x.php.stub in database/migrations and call hasMigration('create_x') without the extension. For auto-loaded migrations, add runsMigrations(). For all migrations, use discoversMigrations(), optionally with path:. Publish tag: <short-name>-migrations; published files get a timestamp prefix. Choose either publishable stubs or auto-run migrations, not both blindly.

  • Routes: place web.php or admin.php in routes/ and call hasRoute('web') or hasRoutes(['web', 'admin']). Middleware, prefixes, and route names stay in the route file. After route changes, run php artisan route:clear.

  • Views, translations, assets, components: hasViews() publishes under <short-name>-views; hasTranslations() under -translations; hasAssets() copies resources/dist to public/vendor/<package-name> under -assets; hasViewComponents('prefix', ...) publishes under -components. Reference package views with the namespace, e.g. view('your-package-name::alert'), and components as <x-prefix-alert />.

  • Commands and installer: register with hasCommand() or hasCommands(). Add an installer command as the primary onboarding workflow:

->hasInstallCommand(function (InstallCommand $command) {
    $command
        ->publishConfigFile()
        ->publishAssets()
        ->publishMigrations()
        ->copyAndRegisterServiceProviderInApp()
        ->askToStarRepoOnGitHub();
});

This gives users one <package>:install command. Add publishInertiaComponents(), publishViewComponents(), publishTranslations(), or publishViews() as needed.

  • Publishable provider: publishesServiceProvider('MyProviderName') expects resources/stubs/MyProviderName.php.stub. Publish tag: <short-name>-provider. The installer can copy and register it with copyAndRegisterServiceProviderInApp().

  • Inertia: hasInertiaComponents() registers resources/js/Pages. Render with Inertia::render('YourPackageName/myComponent'). Publish tag: <short-name>-inertia-components, or publish through the installer.

  • Lifecycle hooks: keep configurePackage() declarative. Use packageRegistered() for container bindings and singletons, and packageBooted() for event listeners, route model bindings, or work that must happen after all providers boot. Complex setup belongs in dedicated providers.

  • Testing workflow: use Orchestra Testbench or a throwaway Laravel app. Assert that vendor:publish --tag=... creates the expected files, and clear config/route caches between runs. For package upgrades, vendor:publish --tag=... --force is the normal refresh path, but warn users that it overwrites files.

Gotchas and Tips

  • name() is mandatory. If the package name starts with laravel-, the prefix is stripped for the short name used in config filenames and publish tags. For example, laravel-cool-package expects config/cool-package.php and tag cool-package-config. This trips people up constantly.

  • The package is opinionated about structure. All custom paths except discoversMigrations() are relative to the primary service provider (src/), not the package root. A custom folder at <root>/ConfigFiles is ../ConfigFiles. The skeleton avoids most path issues; non-standard packages may need a custom provider.

  • The config filename must match the short name. If it does not, pass the explicit name to hasConfigFile('actual-name'). After publishing config, run php artisan config:clear; cached config will otherwise hide changes.

  • Migration names are passed without .php or .php.stub. Publishing prefixes timestamps. runsMigrations() loads migrations directly; if you also tell users to publish migrations, you can end up with duplicate migrations. Pick one strategy and document it.

  • Publish tags are the public API of your install experience. Verify each one: <short-name>-config, -migrations, -assets, -views, -translations, -components, -inertia-components, -provider. Typos in tags are silent until a user reports missing files.

  • vendor:publish --force overwrites user-customized files. In installer commands, prefer explicit publish methods and clear prompts; do not make --force the default.

  • Assets are not built by this package. resources/dist must already contain compiled files; hasAssets() only copies them to public/vendor/<package-name>. Vite/Webpack setup remains your responsibility.

  • Published views, components, and translations are for customization, but do not assume Laravel automatically switches to the published copy. Verify namespace/component registration when users override files, or document that they must re-register.

  • Routes are loaded from the package, not published. If route caching is enabled, stale routes persist until route:clear. A missing route file will fail at boot, so only register files that exist.

  • The installer command is the best extension point for UX, but keep it idempotent. Users run it on fresh installs and upgrades; avoid destructive overwrites and check for existing files where possible.

  • For debugging, start with php artisan vendor:publish --provider="Your\Package\ServiceProvider" to confirm the provider is discovered, then test individual tags. If config is not merging, check the filename and short name. If views are not found, check the namespace and resources/views path.

  • Extension points beyond the manifest: override packageRegistered() and packageBooted(), add dedicated providers for bindings and events, and use Package methods only for standard Laravel package wiring. Do not put business logic in configurePackage(); it runs early and should stay cheap.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core