Open source
Messages for Laravel
composer require roundly-consulting/messages-for-laravelOverview
A direct-message and group-chat foundation for Laravel. Give any Eloquent model a one-line messaging API through the Messages facade or a model trait — 1:1 DMs, group threads with roles, replies, private file attachments, read receipts and unread counts — react to plain Laravel events, and optionally broadcast every change in real time. MIT-licensed and built only on Laravel plus Roundly’s own enums, media-library and package-toolkit packages — no third-party runtime dependencies.
What you get
One-line DMs & group chats
conversationWith() find-or-creates the single DM between two models; startConversationWith() opens a group. Participants are polymorphic.
Roles & moderation
Owner, admin and member roles on group threads, ownership transfer, rename and archive — with typed exceptions, skipped for DMs.
Read receipts & inbox
Per-participant read pointers, unread counts, seen-by lists and a paginated inbox that renders without N+1 queries.
Replies & private attachments
Quote snapshots that survive edits and deletes, plus private file attachments served only through short-lived signed URLs.
Events & optional realtime
Plain Laravel events fire on every write. Flip one env var to broadcast threads, messages, reads and typing over Reverb, Pusher or Ably.
Notifications & API resources
Opt-in new-message notifications through Laravel’s own channels, and drop-in JSON resources for an API or SPA backend.
Facade, DI or actions — and a recording fake
Call the Messages facade, inject MessagesManager or run an action. Messages::fake() records every call, whichever way it came in.
Documentation
Installation
Install via Composer, publish the publish-only migrations for messages and media-library, then migrate.
Configuration
Every config key and its default — models, key types, publicity, attachments, roles, notifications, previews, pruning and broadcasting.
Key types
Choose bigint, UUID or ULID keys for the messaging tables and for the sender and participant morph columns — before you migrate.
Preparing your models
Implement ParticipatesInMessaging and add HasMessaging to any model that sends messages or takes part in threads.
The Messages facade
The whole API on one facade — thread and message builders, DMs, read state, listings, thread, participant and message handles, and pruning.
DI, actions, DTOs & exceptions
Inject MessagesManager or run the actions yourself — the facade-to-action map, the DTOs they take and the typed exceptions they throw.
Direct messages
Find-or-create the single 1:1 thread between two participants with one call — always private, never duplicated.
Group conversations
Start named group threads, set public and join flags, and add, remove or let participants leave.
Roles & permissions
Owner, admin and member roles on group threads — who may add, remove, rename, archive and moderate, and how enforcement works.
Replies & quoting
Reply to any message in the same thread; a quote snapshot is stored on the reply so it survives edits and deletes.
Attachments
Private file attachments backed by media-library — send with a message, read them back, and serve them via short-lived signed URLs.
Inbox & read receipts
A paginated, N+1-free inbox with per-thread unread counts, plus read pointers, seen-by lists and unread checks.
Editing & system messages
Edit and unsend messages with typed guards, and write translatable system messages that render in any locale.
Events
Plain Laravel events fire from every write path — with or without broadcasting — for notifications, search indexing and activity logs.
Broadcasting
Push threads, participants, messages and typing live over Reverb, Pusher or Ably — off by default, fully configurable channels and names.
Notifications
Opt in to bridge every new message to Laravel notifications for the thread’s other participants — your class, your channels.
Models & queries
The Thread, Message and Participant models — query scopes, relations, helpers, paginated listings and swapping in your own subclasses.
API resources
Drop-in JSON resources for threads, messages and participants — safe fields only, read state and reply info included.
Artisan commands
Prune old messages for retention or privacy with messages:prune, and inspect the configuration with php artisan about.
Testing
Messages::fake() records every operation for assertions, plus factory states, the InteractsWithMessaging trait and Pest expectations.
Requirements
PHP 8.4+, Laravel 12 or 13, and three sibling Roundly packages installed automatically.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.