rtippin/messenger
Laravel Messenger adds a complete messaging system to your app: private and group conversations, real-time broadcasts, attachments, reactions, read receipts, and notifications. Eloquent-driven, customizable, and easy to integrate with any Laravel project.
Minimal path from zero to a working private thread:
Install the package
composer require rtippin/messenger
php artisan messenger:setup
messenger:setup publishes the config, migrations, and frontend assets and runs migrations. If you prefer manual control, publish the individual tags:
php artisan vendor:publish --tag=messenger.config
php artisan vendor:publish --tag=messenger.migrations
php artisan vendor:publish --tag=messenger.assets
php artisan migrate
Make your authenticatable model a messenger provider
Add the trait and implement the contract on App\Models\User:
use RTippin\Messenger\Contracts\Messenger;
use RTippin\Messenger\Traits\HasMessenger;
class User extends Authenticatable implements Messenger
{
use HasMessenger;
}
Register the provider in config/messenger.php
Add your model and its morph alias under providers:
'providers' => [
App\Models\User::class => 'user',
],
If you use multiple provider models (e.g. User, Team), register each one and enforce a matching morph map.
Configure broadcasting and a queue worker
Real-time messaging is delivered through Laravel broadcasting events:
BROADCAST_CONNECTION=reverb
QUEUE_CONNECTION=redis
php artisan queue:work
First use case: create a private thread and send a message
use RTippin\Messenger\Facades\Messenger as MessengerFacade;
$thread = MessengerFacade::threads()->create(
[
'owner_id' => $user->id,
'owner_type' => $user->getMorphClass(),
'type' => 'private',
],
[
$other->id => $other->getMorphClass(),
]
);
MessengerFacade::messages()->send($thread, $user, 'Hello!');
Listen on the client with Echo:
Echo.private(`messenger.thread.${threadId}`)
.listen('.message.created', (e) => {
console.log(e.message);
});
The package also ships API routes (default prefix /api/messenger) protected by auth, so a SPA can use HTTP endpoints instead of the facade.
Facade for backend workflows, API for frontend workflows. Use Messenger::threads(), Messenger::messages(), Messenger::participants(), and Messenger::calls() for server-side operations (seeders, bots, admin panels). Use the package’s HTTP routes from your SPA or mobile client so you inherit the package’s authorization, validation, and broadcast behavior.
Private vs group threads. Threads are created with a type of private or group. A private thread takes exactly one other participant; a group thread takes an array of participants and optional name, avatar, and invite settings. Creation through the facade is:
Messenger::threads()->create($attributes, [
$participant->id => $participant->getMorphClass(),
]);
Message composition. Text, replies, attachments, and reactions are handled separately:
Messenger::messages()->react(...)-style calls add emoji reactions.Keep uploads and message sends in separate requests so failed uploads do not create empty messages.
Bots are scheduled, not automatic. Implement the MessengerBot contract, register the bot class in config/messenger.php under bots, then schedule the bot command:
// app/Console/Kernel.php or routes/console.php
$schedule->command('messenger:bots')->everyMinute();
Bots are useful for welcome messages, moderation, canned responses, and thread automation. They only run when the command is scheduled and the queue worker is running.
Real-time integration. The package broadcasts events such as message.created, message.reaction, and call signaling events on private channels like messenger.thread.{threadId}. Listen with Echo and update local state from the event payloads rather than re-fetching the whole thread after every message.
Calls use WebRTC signaling. Configure STUN/TURN servers in config/messenger.php, then use the package’s call endpoints and listen for call events on the thread channel. The package handles signaling; you still need a TURN server for reliable production calls.
Authorization hooks. The package checks thread participation and the authenticated Messenger provider. Add domain rules through Laravel gates/policies and the package’s events rather than editing vendor code. For example, gate group creation or restrict who can add participants.
Extension points. Prefer:
RTippin\Messenger\Events\* for auditing, notifications, or integrations.Missing trait or contract breaks everything. If your User model does not use HasMessenger and implement Messenger, thread creation and provider resolution fail. This is the most common setup mistake.
Morph map mismatch. If you use Relation::enforceMorphMap(), the morph aliases must match the aliases registered in config/messenger.php. A mismatch causes participants to be stored with one type and queried with another.
Clear config cache after editing providers or bots. config/messenger.php is cached in production. Run php artisan config:clear after adding a bot or provider; otherwise the package will not see it.
Broadcasting silently does nothing without a queue worker. The events implement ShouldBroadcast; if your queue is not running or is misconfigured, messages persist but clients never receive them. Check BROADCAST_CONNECTION, QUEUE_CONNECTION, and the channel authorization callback.
Channel authorization uses the default broadcast auth route. Ensure Broadcast::routes(['middleware' => ['web', 'auth']]) is registered and that your Echo client authenticates with the same session/CSRF setup.
Migration conflicts. The package publishes threads, messages, participants, and related tables. If your app already has tables with those names, rename the package tables in config or use a table prefix before running migrations.
Attachment disk defaults. The default attachment disk is often public. For private files, switch to s3 or a private disk and verify signed URL generation. Also configure max upload size and image dimensions; large uploads otherwise fail at the PHP/web-server level rather than with a clear validation error.
Bots need both scheduling and a queue. Scheduling messenger:bots without a running queue worker means bot actions are dispatched but never processed. Start with QUEUE_CONNECTION=sync in local development if you want immediate execution, then move to Redis/database in production.
Calling needs TURN for production. The default STUN configuration is fine for local testing but will fail for users behind symmetric NATs. Configure a TURN server before shipping calling features.
Use events instead of modifying vendor code. Listen to package events for notifications, analytics, and integrations. This keeps upgrades safe and avoids forking the package.
Rate-limit and throttle the API routes. Messenger endpoints can create threads, upload files, and send messages. Add throttle middleware to config('messenger.routes.middleware') or your route group to prevent abuse.
Frontend assets are optional. The package ships assets for its own UI, but the API is usable headlessly. If you are building a custom frontend, you can skip asset publishing and consume the JSON endpoints directly.
How can I help you explore Laravel packages today?