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.
Architecture fit. spatie/laravel-package-tools is a build-time/runtime base class for package authors, not an application feature library. It supplies an abstract PackageServiceProvider plus a fluent Package configuration object that centralizes registration of config files, views, view components, migrations, routes, commands, translations, assets, Inertia components, publishable service providers, install commands, and lifecycle hooks. The fit question is therefore organizational, not application-level: it pays off only if we build and maintain reusable Laravel packages internally (domain modules, shared SDKs, tenant/feature packages) rather than a single monolith. Notably, it is a production dependency of each package (the provider ships in the package), so it lands in every consuming app's vendor/ — this is not a dev-only tool like PHPUnit.
Integration feasibility. High. Adoption is a composer require plus extending the base provider and replacing hand-rolled register()/boot() boilerplate with fluent calls. The package is explicitly opinionated about directory layout (config/, database/migrations/, resources/views/, resources/dist/, routes/) and about path resolution being relative to src/ (e.g. ../ConfigFiles), so porting existing packages is mechanical but not zero-effort — expect a few hours per package plus verification of publish tags.
Technical risk.
laravel- prefix stripped), so naming discipline across packages is a real constraint.dependents: 0 is almost certainly an artifact — this package is a transitive dependency of a large share of Spatie's ecosystem and of most teams already using Spatie packages. Validate via Packagist reverse dependencies before treating "low adoption" as a risk signal.Key questions.
copyAndRegisterServiceProviderInApp, publishable providers) or only config/views/migrations/routes?Stack fit. Composer-based Laravel packages across Laravel 9–12 / PHP 8.x (confirm exact matrix from composer.json, not the README). Distribution method is irrelevant — Packagist, private registry, or path/VCS repositories all work. It composes cleanly with existing conventions and does not force a DI or architecture pattern; it only standardizes registration.
Migration path.
ServiceProvider in internal packages and classify calls into "covered by the fluent API" vs "bespoke logic to keep in register()/boot()."register()/boot().vendor:publish --tag=<name>-config|views|migrations|assets), plus runsMigrations() vs publish-then-migrate behavior.spatie/package-skeleton-laravel so new packages start compliant.Compatibility. Pin ^X.Y per package via a shared constraint in the monorepo or a documented standard; add a CI job asserting the constraint resolves against the oldest and newest supported Laravel majors. Because the library is a runtime dependency, version skew across packages will surface as conflicting constraints in consuming apps — keep all internal packages on the same major.
Sequencing. (a) Validate support matrix and reverse-dependency reality → (b) internal skeleton + written convention → (c) pilot package → (d) shared publish-tag naming scheme to prevent collisions → (e) CI template (test matrix + publish smoke test) → (f) bulk migration → (g) scheduled major-upgrade rehearsal.
Maintenance. Low steady-state cost: the library abstracts boilerplate we would otherwise hand-write. The real recurring cost is major-version upgrades aligned to Laravel majors, plus convention drift if teams fork or partially adopt. Budget one focused upgrade task per Laravel major, not continuous maintenance.
Support. Community-only: GitHub issues, changelog, releases; no vendor SLA. Mitigations: pin versions, vendor the constraint centrally, and note that MIT + a bounded, mechanical surface means the exit cost is low — worst case, drop the base class and hand-roll providers (a known, scoped effort, roughly the same as the original port).
Scaling. Value scales with package count: more packages means more consistency gain (uniform publish tags, uniform install UX, faster new-package bootstrap) and fewer bespoke onboarding docs. Runtime cost is limited to provider boot work — negligible for normal apps, but worth a look if we run Octane or long-lived workers and do anything non-trivial in boot() or rely on config merging with config:cache.
Failure modes to monitor.
runsMigrations() and published migrations are in play.laravel- prefix.copyAndRegisterServiceProviderInApp) breaking unattended CI or re-runs — gate these behind interactive use.Ramp-up. A Laravel-fluent engineer is productive in well under a day; the learning curve is the directory convention and publish semantics, not the API. Plan a short internal guide, the skeleton repo, and one reference implementation. Total organizational ramp is effectively one sprint for the pilot plus one package per engineer-day thereafter.
TPM recommendation. Adopt as a Tier-3 internal standard with a pinned major, an internal skeleton, and a publish smoke test in CI — contingent on confirming (1) the Laravel support matrix, (2) that we maintain enough packages to justify the convention, and (3) that the dependents: 0 figure is the data artifact it appears to be. Do not adopt the install-command/publishable-provider features until the config/views/migrations/routes core is proven.
How can I help you explore Laravel packages today?