# How the Ghost Comments System Works: Architecture, Features, and Moderation

> Explore the Ghost comments system architecture, features, and moderation tools. Learn how Ghost handles comments with its robust three-layer design and powerful admin controls.

- Repository: [Ghost/Ghost](https://github.com/TryGhost/Ghost)
- Tags: architecture
- Published: 2026-05-18

---

**Ghost implements a full-stack comments feature using a three-layer architecture of service, controller, and API endpoints, with moderation capabilities including bulk actions, reporting, and status management accessible through both member and admin contexts.**

The Ghost comments system is built into the core of the TryGhost/Ghost repository as a native feature rather than an external plugin. It provides a complete solution for member engagement with sophisticated content gating, email notifications, and administrative moderation tools.

## Core Architecture of the Ghost Comments System

Ghost organizes its comments functionality into three distinct layers that separate business logic from API presentation.

### Service Layer

The `CommentsService` class in [`ghost/core/core/server/services/comments/comments-service.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/server/services/comments/comments-service.js) contains the core business logic. This service handles data access, permission checks, email notifications, and all CRUD operations. Key methods include `commentOnPost` (line 309), `replyToComment` (line 667), and `bulkUpdateStatus` (lines 506-516). The service also dispatches domain events like `MemberCommentEvent` to allow other Ghost subsystems to react to comment activity.

### Controller Layer

The `CommentsController` in [`ghost/core/core/server/services/comments/comments-controller.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/server/services/comments/comments-controller.js) translates API frames into service calls. It handles request validation, extracts member context from authentication frames, and manages impersonation for admin routes. The controller also sets cache-invalidation headers (`X-Cache-Invalidate`) via `handleCacheHeaders` to ensure CDN cache consistency after mutations.

### Endpoint Layer

The API routes are declared in [`ghost/core/core/server/api/endpoints/comments.js`](https://github.com/TryGhost/Ghost/blob/main/ghost/core/core/server/api/endpoints/comments.js), which maps HTTP endpoints such as `/comments`, `/comments/browse`, and `/comments/report` to controller methods. This file wires the public-facing routes to the underlying controller logic.

## Enabling and Access Control

Comments are gated by the **`comments_enabled`** setting, which the service checks via the `checkEnabled()` method (lines 56-61). This setting supports three values:

- **off** – All comment actions are blocked; the service throws a `MethodNotAllowedError`
- **all** – Any signed-in member may comment
- **paid** – Only members with active paid subscriptions may comment

All public comment actions—including `commentOnPost`, `replyToComment`, and `likeComment`—invoke this guard before proceeding.

### Content Gating for Paid Members

When `comments_enabled` is set to `paid`, the service performs additional validation through `checkCommentAccess` (lines 66-70) to verify the member's subscription status. The `contentGating.checkPostAccess` call (lines 74-80) also enforces any paywall restrictions on the target post itself, ensuring comments respect the post's visibility settings.

## Comment Lifecycle and CRUD Operations

### Creating Comments and Replies

When a member posts a comment, the flow proceeds through three stages:

1. **Controller validation**: The `add` method in [`comments-controller.js`](https://github.com/TryGhost/Ghost/blob/main/comments-controller.js) validates the payload and forwards it to the service via `commentsService.api.commentOnPost` or `replyToComment`
2. **Service processing**: The service fetches member and post models, checks access permissions, builds the comment payload, and persists it via `models.Comment.add`
3. **Post-persistence**: The service triggers `sendNewCommentNotifications` and dispatches a `MemberCommentEvent` for analytics

The system differentiates between top-level comments (`commentOnPost`) and threaded replies (`replyToComment`).

### Reading and Browsing Comments

For public consumption, `CommentsController.browse` builds filters for specific `post_id` values and delegates to `service.getComments`, which uses `models.Comment.findPage` (lines 74-78). For reply threads, `CommentsController.replies` invokes `service.getReplies`, which also leverages `findPage` with `parentId` filtering.

### Editing and Deleting Comments

Administrators and members can modify comments through specific service methods:

- **`deleteComment`** (lines 452-506): Changes the comment status to `deleted` rather than physical removal
- **`editCommentContent`** (lines 452-506): Updates the HTML content and sets the `edited_at` timestamp to track modifications

## Comment Moderation in Ghost

The Ghost comments system provides comprehensive moderation capabilities through the admin API, accessible even when the global `comments_enabled` setting is `off`.

### Admin Browse and Filtering

The `adminBrowseAll` controller method calls `service.getAdminAllComments` (lines 202-215) to return paginated lists of all comments with optional nested replies (`includeNested` parameter). This allows moderators to view the complete comment history regardless of post or status filters applied to public endpoints.

### Reporting and Managing Reports

Members can report inappropriate content through the `reportComment` method (lines 147-169), which:

1. Persists a `CommentReport` record in the database
2. Triggers an email notification to staff via `notifyReport`

Administrators can view who reported a specific comment using `getCommentReporters` (lines 240-258) and see engagement metrics through `getCommentLikes` (lines 262-280), which returns the member list of users who liked a comment.

### Bulk Moderation Actions

For efficient content management, the service provides `bulkUpdateStatus` (lines 506-516), which accepts an NQL filter and a target status. This allows administrators to hide, publish, or delete multiple comments simultaneously based on criteria such as member ID or date ranges.

### Cache Invalidation

All mutation endpoints in the controller set `X-Cache-Invalidate` headers to trigger CDN purge events. This ensures that cached comment fragments on the frontend are immediately cleared when content is moderated or updated.

## Email Notifications and Events

The comments system integrates with Ghost's email infrastructure through `CommentsServiceEmails` ([`comments-service-emails.js`](https://github.com/TryGhost/Ghost/blob/main/comments-service-emails.js)). New comments trigger notifications to:

- Post authors via `notifyPostAuthors`
- Parent comment authors (for replies) via `notifyParentCommentAuthor` 
- Staff members when reports are filed via `notifyReport`

These emails are rendered using templates from [`comments-service-email-renderer.js`](https://github.com/TryGhost/Ghost/blob/main/comments-service-email-renderer.js).

## Permission Model and Impersonation

Public comment routes require an authenticated member context, extracted from `options.context.member.id` via the `checkMember` method. 

Because the admin UI operates on a different subdomain, the controller supports impersonation through the `impersonate_member_uuid` parameter (lines 28-34). This allows administrators to perform actions like liking comments on behalf of specific members while respecting member-specific logic and permissions.

## Summary

The Ghost comments system provides a production-ready engagement platform with the following capabilities:

- **Three-tier architecture** separating service logic, API controllers, and HTTP endpoints for maintainability
- **Flexible access control** supporting fully open, member-only, or paid-subscriber-only commenting
- **Complete moderation tooling** including bulk updates, reporting workflows, and audit trails with `edited_at` tracking
- **Integrated email notifications** for authors, reply recipients, and staff alerts
- **Cache-aware mutations** with automatic CDN invalidation through `X-Cache-Invalidate` headers
- **Admin impersonation** support for cross-domain management actions

## Frequently Asked Questions

### How do I enable comments on a Ghost site?

Comments are controlled by the `comments_enabled` setting in your Ghost admin panel. Set it to `all` to allow any member to comment, `paid` to restrict commenting to paid subscribers only, or `off` to disable the feature entirely. According to the source code in [`comments-service.js`](https://github.com/TryGhost/Ghost/blob/main/comments-service.js), changing this setting immediately affects all comment endpoints without requiring a restart.

### Can administrators edit or delete member comments?

Yes. The `CommentsService` provides `editCommentContent` and `deleteComment` methods that administrators can access through the admin API. The `deleteComment` method performs a "soft delete" by changing the status to `deleted` rather than removing the record, preserving the thread structure. Bulk operations are supported via `bulkUpdateStatus` using NQL filters to target specific comment sets.

### How does Ghost handle inappropriate comment reports?

When a member reports a comment via the `/comments/{id}/report/` endpoint, the `reportComment` method (lines 147-169) creates a `CommentReport` record and sends an email notification to staff. Administrators can then view the list of reporters through `getCommentReporters` and take moderation action using the standard bulk or individual status update tools.

### What happens when a comment is posted on a paid-only post?

If `comments_enabled` is set to `paid`, the service executes `checkCommentAccess` to verify the member has an active paid subscription. Additionally, `contentGating.checkPostAccess` ensures the member has access to the post content itself before allowing the comment to be created. This dual-check prevents comment leakage on gated content.