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

Laravel Comments Laravel Package

spatie/laravel-comments

Laravel Comments lets you associate comments with any Eloquent model, so you can add threaded discussion to posts, products, or other records with minimal setup. Configurable, tested, and maintained by Spatie.

View on GitHub
Deep Wiki
Context7

Getting Started

Start with the hosted docs, not the README — the README is a stub pointing at https://spatie.be/docs/laravel-comments, and the useful pages are Installation, Adding comments to a model, Reactions, Notifications and Mentions.

composer require spatie/laravel-comments
php artisan vendor:publish --tag="comments-config"
php artisan vendor:publish --tag="comments-migrations"   # inspect the stub before migrating
php artisan migrate

Then three wiring steps, in this order:

  1. Config — config/comments.php is the real API surface. Note the model mappings (comment model, commentator model, reaction model, notification classes) and the behaviour switches (auto-approval, guest comments, validation rules, gravatar/FontAwesome, sanitizer). Change class mappings before you migrate in anger; changing the comment model later means a data migration.
  2. Traits — put the package's "has comments" trait on the commentable model(s) (e.g. Post), and the commentator trait on User (or whatever you point the config at). One trait gives you the comments morph-many relation; the other lets a user author/receive comments.
  3. First use case — a single discussion thread on a Post page. Either drop in the shipped Blade component (<x-comments::comments :model="$post" />-style, per the docs page for your version) to get form + list + reactions for free, or ignore the views and call the model API directly from your own controller when you need custom auth, throttling, or an Inertia/JSON response.

Before writing a line of app code, open vendor/spatie/laravel-comments/src for ten minutes. The public docs are good but thin on edge cases, and this is a small-adoption package (32 stars, 0 dependents in this snapshot) — the source is the secondary documentation.

Implementation Patterns

One morph relation, many commentable types. This is a polymorphic package by design: enable comments on Post, Page, Ticket and query per-type. Register an explicit morph map in a service provider early; the package has historically needed it for helper methods such as resolving comment participants (see the 1.7.1 fix), and it keeps your commentable_type column sane.

Threaded discussions. Comments carry a parent reference, so replies are first-class: render top-level comments with children eager-loaded, and let the package's reply notifications handle the "someone answered you" mail. Don't build your own reply table on top.

Reactions as a separate axis. Reactions live alongside comments, not inside them: $comment->react(...), a hasReacted-style check, and aggregated counts. Typical pattern is a toggle endpoint (react/unreact) that returns the new count, with the UI optimistic and the server authoritative. If you only need likes, skip reactions entirely — it's optional surface area.

Authorize at the edges, not in the package. The shipped controllers do the obvious thing, but real apps need policies: who may edit/delete a comment, who may comment on a locked thread, who may approve. The cleanest pattern is a thin app-level controller that checks a Gate/policy and then delegates to the package's models, or publishes the views and wraps the form in @can.

Moderation as a state machine. Auto-approve is a config flag; for anything public-facing flip it off and gate visibility on an approved scope/attribute, with an admin action to approve/disapprove. Combined with mentions and notifications, this is the difference between a demo and a shippable comment box.

Notifications. Point the config's notification classes at your own subclasses (extends the package notifications), implement ShouldQueue, and route per-channel. The package respects a "disable notifications" preference on the user — honour it in anything you add.

Custom models. Extending the base Comment and remapping the config is the supported extension point: add scopes, casts, LogsActivity, or a rendered_html accessor there rather than in a wrapper. Same for the reaction model. Watch the custom-model-key support if you use UUID/ULID keys.

Frontend reality check. The shipped UI is server-rendered Blade with a JS sprinkle and (by default) pulls assets from a CDN. If you're on Livewire, Inertia, or a design system, budget for publishing the views or building your own UI on the model API — that's usually less work than fighting Tailwind classes you don't own.

Gotchas and Tips

  • The Blade components are the loudest part of the package and the least portable. They assume Tailwind-ish markup and FontAwesome; there's a config switch to stop the automatic FontAwesome download. Self-host assets and publish views (--tag="comments-views") or the first CSP audit will be unpleasant.
  • XSS and sanitization are config-dependent. Rendering is markdown/HTML-adjacent and there's an explicit sanitizer option plus a past XSS fix (1.0.7). If you accept rich text, verify the sanitizer setting rather than trusting the default, and test with <img onerror>.
  • Updating comments without transformers was a real bug (fixed 1.2.1) — if you add a transformer/renderer, write an edit-path test, not just a create-path test.
  • Morph map surprises. Comment participants/notification recipients can break when commentable_type is a raw FQCN. Register the morph map before you seed data.
  • Notification edge cases are where the history lives. Reply notifications, the "disable notifications" preference, and user-reaction relation naming have all been patched at some point (1.4.4, 1.4.6, 1.4.7, 1.4.10). When notifications misbehave, read the changelog first — you're probably not the first.
  • Pin majors and read the upgrade notes. v1 → v2 changed requirements/namespaces; v2.1 bumped the markdown/commonmark chain, v2.2 added Laravel 12, v2.3 bumped the HTML sanitizer. A ^2.3 constraint is reasonable today; blindly floating across majors is not.
  • N+1 on comment lists. Always with('commentator') and withCount('reactions') (or eager-load reactions) before rendering a thread; a 50-comment page with lazy gravatars and per-row reaction queries will crawl.
  • Guest comments + gravatar. Guest commenting makes the commentator relation nullable; every "who wrote this" branch in your UI must handle null. Set an explicit gravatar fallback rather than shipping mystery-person icons.
  • Rate limiting and spam are yours. The package is not a spam filter — put throttle middleware on your comment endpoint and consider honeypot/akismet-style checks before the model is touched.
  • Small install base means you're the QA. Actively maintained by Spatie with a real test suite (composer test), MIT licensed, releases through 2026 — but 0 dependents means few Stack Overflow answers. Budget time to read source and write feature tests around approval, edits, deletion, and notifications before you ship publicly.
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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager