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

Alerts Laravel Package

cartalyst/alerts

Cartalyst Alerts is a lightweight Laravel package for managing flash notifications. It stores alerts in the session, supports success, error, warning, and info levels, and provides helpers to add, retrieve, and render them in your views.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm what you actually got.

composer require cartalyst/alerts
php artisan vendor:publish --provider="Cartalyst\Alerts\AlertsServiceProvider"

Auto-discovery registers the provider; the publish step gives you config/cartalyst.alerts.php (alert types, the Blade view used for rendering, and the session key). Before writing any code, spend ten minutes in vendor/cartalyst/alerts/ — read the facade class and the shipped view. The README advertises more than the narrow flash-to-Blade use case, so confirm first-hand that the version you installed is the thin one (add message → session → render partial) and not a subscriber/transport system. Everything downstream depends on that answer.

First use case: post-redirect-get feedback. This is the whole job.

// app/Http/Controllers/ProfileController.php
public function update(UpdateProfileRequest $request)
{
    $request->user()->update($request->validated());

    Alerts::success('Profile updated.');

    return redirect()->route('profile.edit');
}

Render once, in your layout, above the content slot:

{{-- resources/views/layouts/app.blade.php --}}
<main>
    {!! Alerts::display() !!}
    @yield('content')
</main>

The facade also exposes error(), warning(), info(), and a generic add($type, $message) — check the exact render method name (display() vs render()) against the installed source, since it has moved between majors.

Verify immediately with a feature test, before you refactor a single existing view:

public function test_profile_update_flashes_success_alert()
{
    $this->actingAs($user)
        ->patch('/profile', ['name' => 'Ada'])
        ->assertRedirect('/profile')
        ->assertSessionHas('cartalyst.alerts');

    $this->followingRedirects()
        ->get('/profile')
        ->assertSee('Profile updated.');
}

If that test passes and the markup escapes Ada-style user-influenced strings, the package is fit for purpose. If either fails, stop and write the ~50-line in-house version instead.

Implementation Patterns

Wrap it. This is a condition of adoption, not a style preference. With 26 stars and zero known dependents, the exit path is the main architectural decision. Reference the Cartalyst facade in exactly one file:

// app/Support/Alert.php
namespace App\Support;

use Cartalyst\Alerts\Facades\Alerts as CartalystAlerts;

final class Alert
{
    public static function success(string $message): void
    {
        CartalystAlerts::success($message);
    }

    public static function error(string $message): void
    {
        CartalystAlerts::error($message);
    }
    // ...
}

Then render through your own Blade component so your markup, not theirs, ships:

{{-- resources/views/components/alerts.blade.php --}}
@foreach (['success' => 'green', 'error' => 'red', 'warning' => 'amber', 'info' => 'blue'] as $type => $colour)
    @foreach (Alerts::get($type) as $message)
        <div class="rounded p-4 bg-{{ $colour }}-50 text-{{ $colour }}-800" role="alert">
            {{ $message }}
        </div>
    @endforeach
@endforeach

This means you never actually render the vendor view in production — publish it only to see which accessors it calls, then reimplement. It also removes the CSS-class collision risk in one move.

Place the call at the HTTP edge. Controllers, form requests, middleware, and the exception handler's render() are the right homes. Do not fire alerts from models, domain services, or queued jobs — the session doesn't exist there, and you'll get silent no-ops or, worse, a Session store not set on request exception.

Exception handler integration gets you consistent failure UX almost for free:

// app/Exceptions/Handler.php
public function register(): void
{
    $this->renderable(function (DomainException $e, $request) {
        Alert::error($e->getMessage());
        return back()->withInput();
    });
}

Multi-message screens (bulk import: 42 succeeded, 3 failed) work naturally — call Alert::success() and Alert::warning() on the same request and let the component loop. Agree a type ordering with design once and encode it in the component, not at each call site.

Auth and middleware flows are a strong second use case — email-verified banners, "your session expired" messages, impersonation notices. Anything that already redirects is a candidate.

Localize at the call site (Alert::success(__('profile.updated'))), not at render. The render path has no idea what locale the action ran in, and translating in a Blade loop is how you end up with untranslated strings leaking into production.

Test at the boundary, not the internals. Assert the flashed session key and the rendered text; never assert against Cartalyst\Alerts\* classes, or your tests become part of the coupling you were trying to avoid.

Gotchas and Tips

Escaping is the one thing to check with your own eyes. Alert strings routinely carry user-influenced content — entity names, validation text, exception messages. Open the vendor Blade view and confirm the message is passed through {{ }} / e(), not {!! !!}. If it isn't, that's a stored-XSS vector on every redirect, and your own component (above) is the fix.

The session must exist. The package writes to the session store, so any route that flashes must be in the web middleware group. API routes, php artisan commands, and queue workers will fail or silently drop. Console commands that want to hint at a next step should log, not alert.

Watch the flash key and view namespace for collisions. Existing session()->flash('status', ...) conventions and any resources/views/vendor/ overrides can quietly clash. grep for the session key from your published config before you migrate, and pick one convention per screen — half-migrated pages showing two banners is the most common rollout artifact.

Don't route validation errors through it. Laravel's $errors bag and @error directives already own that surface. Duplicating field errors as alerts gives users the same message twice and breaks old() repopulation expectations. Alerts are for outcomes, $errors is for input.

Assume one render, not a queue. The render path consumes/flashes on read in most versions. Rendering the partial twice (layout and a partial, or a cached fragment) can produce duplicated markup or a swallowed message. Render in exactly one place in the layout, and if the version ships a clear()/flush(), call it in test teardown so state doesn't bleed between tests.

This is server-rendered only. Livewire, Inertia, and SPA front ends won't pick this up without a full page reload. In those stacks the correct pattern is a JSON flash payload consumed client-side; only the "collect a message" half transfers, which is native Laravel. Don't force it.

No dismissal, no toasts, no persistence. There's no read/unread, no per-user inbox, no client-side queue. If a stakeholder reads "alert types and notifications" in the vendor copy and schedules a notifications roadmap item, correct it there and then — that's Laravel's Notification system, a different package and a different decision.

Pin the minor version and verify the constraint matrix. A 2025 release adding Laravel 12 support is a good maintenance signal, but one missing major turns this into a fork-and-maintain commitment. Check composer.json against your current and next Laravel major before committing, and don't float the constraint.

Config and view caches bite after publishing. Run php artisan config:clear and php artisan view:clear after editing the config or adding your component override; otherwise you'll debug a change that was never loaded.

Debugging one-liners: Alerts::all() in a controller or session()->all() in tinker shows exactly what's queued. If a message isn't appearing, the order is almost always (1) not in the web group, (2) rendered twice, (3) type not declared in config('cartalyst.alerts.types'), (4) config cache.

Write the exit procedure down. If the package goes quiet, copy the relevant class into app/Support, swap the one file behind your wrapper, delete the dependency. Half a day's work — but only because you kept the facade out of your application and view code.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo