What is a package?
In Laravel, a package is a Composer package that adds functionality to an application. There are two broad categories:- Standalone packages — General-purpose PHP libraries with no Laravel dependency (e.g., Carbon, Pest)
- Laravel packages — Packages with routes, controllers, views, config, and other features tightly integrated with Laravel
When writing tests for a package, use Orchestra Testbench. It lets you write package tests just as you would tests inside a normal Laravel application.
Package auto-discovery
When a package is installed, Laravel reads theextra.laravel section of composer.json and automatically registers service providers and facades.
bootstrap/providers.php — the package is loaded automatically.
Package auto-discovery internals explains how this auto-discovery is implemented and when the cache is rebuilt.
Disabling auto-discovery
Users who want to disable auto-discovery for a specific package can do so in their application’scomposer.json.
The role of service providers
A service provider is the entry point for a package. It is where you centralize the registration of views, config, migrations, routes, and other resources with Laravel. Service providers extendIlluminate\Support\ServiceProvider and have two methods: register and boot.
callAfterResolving() runs and how to design for repeated application.
To register services so that no state carries over in Octane or queue workers, see Package service lifetime design. It explains how scoped() works internally and the caveats around dependencies held by singletons.
Publishing config files
publishes() — publish files
Callingpublishes() in the boot method allows users to copy config files into their application with the vendor:publish command.
mergeConfigFrom() — merge with defaults
UsingmergeConfigFrom() in the register method ensures that the package’s default values are used even when users have not published the config file.
Organizing with publish tags
Pass a tag as the second argument topublishes() so users can choose which resources to publish.
Registering routes
UseloadRoutesFrom() to load a routes file. It is automatically skipped when the application’s route cache is active.
Publishing migrations
UsepublishesMigrations() to register migration files for publishing. In the default Laravel 13 configuration, database.migrations.update_date_on_publish is enabled, so Laravel updates the timestamps in the file names when they are published. If the setting is disabled or missing, Laravel does not update them.
Publishing views
loadViewsFrom() — register views
Register a view directory withloadViewsFrom(). Use the namespace passed as the second argument to reference views with the package::view syntax.
resources/views/vendor/courier in the application; if nothing is found there, it falls back to the package’s view directory. This lets users customize views.
For the lookup order in the implementation, per-file fallback, how to deliver changes to published templates, and how this differs from the Blade cache, see Overriding and updating package views.
Publishing views
Registering Blade components
To include components in your package, register them in theboot method.
Distributing public assets
To distribute your package’s JavaScript, CSS, and images, usepublishes() to register a copy to a location such as public_path('vendor/courier'). Updating the package does not automatically change files that have already been published.
Narrowing the selection by tag and provider, the difference between --force and --existing, how deleted files are handled, and updates through laravel-assets are covered in Package public assets and updates.
Publishing translation files
Register translation files withloadTranslationsFrom(). Reference translations using the package::file.key syntax.
loadJsonTranslationsFrom().
Registering commands
Register Artisan commands for your package using thecommands() method. It is common practice to register them only in a console environment.
Integrating with the optimize command
If your package has its own cache, use theoptimizes() method to integrate with php artisan optimize and php artisan optimize:clear.
--except, execution order relative to the built-in tasks, and exit codes on failure, see Integrating package caches with optimize.
Adding information to the about command
Use AboutCommand::add() to include package information in the output of php artisan about.
--only and JSON output, designs that keep secrets out of the output, and registration state in tests, see Adding package diagnostics to about.
Creating a facade
A facade lets you call service container bindings as if they were static methods.1
Create the service class
2
Create the facade class
Extend
Illuminate\Support\Facades\Facade and return the service container binding key from getFacadeAccessor().3
Bind it in the service provider
4
Register it in composer.json
@method PHPDoc annotations to the facade enables IDE auto-completion.
DeferrableProvider — implementing deferred loading
Providers that only perform service container bindings can implement theDeferrableProvider interface to achieve deferred loading. The provider is not loaded until the service is actually needed, improving application performance.
provides() is resolved.
Testing a package
Use Orchestra Testbench to test your package in isolation. It lets you write tests as if you were inside a normal Laravel application.getPackageProviders() in your test case to register the package’s service provider.
Publishing to Composer
Best practices for publishing your package to Packagist. Basiccomposer.json configuration
Related pages
Service providers
Learn about the
register and boot methods of service providers and the details of deferred providers.Package auto-discovery internals
Learn how
extra.laravel is collected, cached, and loaded through PackageManifest.Package version compatibility
Learn how to manage Laravel and PHP version compatibility for your packages, including GitHub Actions test matrix configuration.