Modules
Comments
The comments module adds a comment thread to any page. Comments are stored in Cloudflare D1, moderated through the admin panel, and pre-rendered to static JSON at build time.
Installation
pnpm add @stedefast/module-comments @stedefast/provider-cloudflare
Setup
// stedefast.config.ts
import { defineConfig } from "@stedefast/core";
import { CommentsModule } from "@stedefast/module-comments";
export default defineConfig({
// ...
modules: [
CommentsModule({
requireApproval: true, // default: true — comments need admin approval
}),
],
cloudflare: {
projectName: "my-site",
d1Databases: [{ binding: "DB", databaseId: "YOUR_D1_DATABASE_ID" }],
},
});
Cloudflare bindings
The comments module requires a D1 database. Create one with Wrangler:
wrangler d1 create my-site-db
Copy the database_id from the output into your config. Then apply the migrations:
wrangler d1 migrations apply my-site-db --local # for dev
wrangler d1 migrations apply my-site-db # for production
Environment variables
Set these in your .dev.vars for local development and as Cloudflare Pages secrets for production:
| Variable | Description |
|---|---|
BETTER_AUTH_SECRET |
Secret used to verify admin requests to the moderation endpoint |
COMMENTS_REQUIRE_APPROVAL |
"true" (default) or "false" — skip moderation queue |
Using the island in a template
The comments island mounts automatically on any page where the module is registered. Add the mount point in your template:
// theme/templates/post.tsx
<div
data-island="CommentsIsland"
data-props={JSON.stringify({ pageId: page.slug })}
/>
The island loads the pre-built comments JSON, renders the thread immediately, and provides a submission form with markdown preview.
How it works
- Build time —
buildStaticExport()queries D1 for all approved comments per page and writesdist/data/comments/<slug>.json - Page load — The island fetches
/data/comments/<slug>.jsonand renders immediately from CDN - Submit —
POST /_modules/comments/submitinserts to D1; the comment is markedpending - Moderate — An admin approves the comment in the admin panel; the D1 row is updated to
approved - Rebuild — On next
stedefast build(or via a deploy hook), the static JSON is regenerated
Moderation
Pending comments are visible in the admin panel at /admin/comments. From there you can approve, reject, or bulk-action the queue.
Typed hooks
The comments module exports typed fetch functions and React hooks from its /hooks subpath. These are what the built-in island uses internally, and what ejected islands import after running stedefast scaffold module-island comments.
import { loadComments, postComment, useComments } from "@stedefast/module-comments/hooks";
import type { Comment, CommentsIslandProps, SubmitCommentBody } from "@stedefast/module-comments";
| Export | What it does |
|---|---|
loadComments(pageId) |
Fetches /data/comments/{pageId}.json — returns Comment[] |
postComment(body) |
POSTs to /_modules/comments/submit — throws on error |
useComments(pageId, initial?) |
React hook wrapping loadComments — returns { comments, loading, error } |
moderateComment(body, token) |
POSTs to /_modules/comments/moderate — for admin use |
Because postComment is typed as (body: SubmitCommentBody) => Promise<SubmitCommentResponse>, if the API changes in a future module version the TypeScript compiler will catch the mismatch in any code that calls it.
Configuration reference
| Option | Type | Default | Description |
|---|---|---|---|
requireApproval |
boolean |
true |
If false, comments are published immediately without moderation |