A value needed in essentially every view — site-wide settings, the current user's unread notification count, a global announcement banner — is tedious to pass explicitly from every single controller method that renders a view. View::share() exists specifically to avoid that repetition.
Sharing a variable from a service provider
// AppServiceProvider::boot()
public function boot(): void
{
View::share('appName', config('app.name'));
}
{{-- available in every single Blade view, automatically --}}
{{ $appName }}
Sharing dynamic, computed data
// AppServiceProvider::boot()
public function boot(): void
{
View::composer('*', function ($view) {
if (auth()->check()) {
$view->with('unreadNotificationCount', auth()->user()->unreadNotifications->count());
}
});
}
View::composer('*', ...) is the more flexible tool for computed, per-request data — the closure runs fresh on every view render, unlike View::share(), which is typically better suited to values that are static or rarely change within a single request lifecycle.
Sharing with a specific view rather than every view
View::composer('layouts.app', function ($view) {
$view->with('categories', Category::all());
});
Passing a specific view name (or an array of names) instead of the '*' wildcard restricts the composer to only run for that particular view — useful when the shared data is only actually needed in a specific layout or partial, not truly every view in the application.
Using a dedicated View Composer class for more complex logic
php artisan make:provider ViewComposerServiceProvider
class NavigationComposer
{
public function compose(View $view): void
{
$view->with('categories', Category::withCount('posts')->get());
}
}
// in a service provider's boot()
View::composer('layouts.navigation', NavigationComposer::class);
Extracting the composer logic into its own class (rather than an inline closure) keeps a service provider's boot() method clean once view composer logic grows beyond a trivial one-liner, and makes the composer logic independently testable.
Why global view data should stay genuinely minimal
Overusing shared view data for things that only a handful of specific views actually need makes it harder to trace where a given Blade variable actually comes from, since it no longer appears explicitly in the controller that renders that view — reserving View::share() and global composers for data that's genuinely needed nearly everywhere (not just "used in a few places") keeps the data flow considerably easier to follow.