Before diving into code, we need to thoroughly understand what we’re building. Comment systems seem simple on the surface, but they involve numerous interconnected challenges.
At its core, a comment is user-generated content associated with a specific page or piece of content. Let’s break down the data model:
┌─────────────────────────────────────────────────────────────┐
│ COMMENT ENTITY │
├─────────────────────────────────────────────────────────────┤
│ id : unique identifier │
│ page_id : which page/article this belongs to │
│ parent_id : for threading (null if top-level) │
│ author : who wrote this │
│ content : the actual comment text │
│ created_at : timestamp │
│ updated_at : if editing is allowed │
│ status : pending/approved/spam/deleted │
│ metadata : IP, user agent, etc. (for spam detection) │
└─────────────────────────────────────────────────────────────┘
Your static site is pre-built. Comments are dynamic. How do you reconcile this?
STATIC SITE DYNAMIC COMMENTS
┌─────────────────┐ ┌─────────────────┐
│ │ │ │
│ Pre-generated │ │ Real-time │
│ at build time │ VS │ user input │
│ │ │ │
│ No server │ │ Needs server │
│ processing │ │ processing │
│ │ │ │
└─────────────────┘ └─────────────────┘
│ │
└────────────────┬───────────────┘
│
▼
┌─────────────────┐
│ │
│ HOW DO WE │
│ BRIDGE THIS? │
│ │
└─────────────────┘
Solutions we’ll explore:
Who is leaving the comment? You have several options:
┌─────────────────────────────────────────────────────────────────┐
│ AUTHENTICATION SPECTRUM │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Anonymous ◄──────────────────────────────────────► Verified │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐│
│ │ │ │ │ │ │ │ │ │ ││
│ │ Fully │ │ Name + │ │ Social │ │ Email │ │ Full ││
│ │Anonymous│ │ Email │ │ OAuth │ │ Verify │ │ Account││
│ │ │ │ (trust) │ │ Login │ │ │ │ ││
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └────────┘│
│ │
│ Lowest More spam Convenient Moderate Highest │
│ friction More abuse Less spam friction friction │
│ Most spam Medium spam Least spam │
│ │
└─────────────────────────────────────────────────────────────────┘
Each approach has trade-offs:
| Method | Spam Risk | User Friction | Implementation Complexity |
|---|---|---|---|
| Anonymous | Very High | None | Low |
| Name/Email (unverified) | High | Low | Low |
| Social OAuth | Medium | Medium | Medium |
| Email verification | Low-Medium | High | Medium |
| Full accounts | Low | Very High | High |
The internet is full of bad actors. Your comment system will face:
┌────────────────────────────────────────────────────────────────┐
│ SPAM ATTACK VECTORS │
├────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Simple │ │ Moderate │ │ Sophisticated│ │
│ │ Bots │ │ Bots │ │ Attacks │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ • Generic spam • Rotate IPs • Solve CAPTCHAs │
│ • Same message • Random delays • Human farms │
│ • Predictable • Vary content • Targeted content │
│ • Easy to block • Harder to catch • Very hard to stop │
│ │
└────────────────────────────────────────────────────────────────┘
Even with good spam prevention, you need human oversight:
┌─────────────────────────────────────────────────────────────────┐
│ MODERATION WORKFLOW │
├─────────────────────────────────────────────────────────────────┤
│ │
│ New Comment │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Spam │──── Spam? ────► Delete / Hold │
│ │ Filter │ │
│ └──────┬──────┘ │
│ │ Clean │
│ ▼ │
│ ┌─────────────┐ │
│ │ Content │──── Toxic? ───► Flag for Review │
│ │ Filter │ │
│ └──────┬──────┘ │
│ │ OK │
│ ▼ │
│ ┌─────────────┐ │
│ │ Auto │──── Trusted? ──► Publish Immediately │
│ │ Approve? │ │
│ └──────┬──────┘ │
│ │ Not trusted │
│ ▼ │
│ ┌─────────────┐ │
│ │ Manual │──► Admin reviews ──► Approve / Reject │
│ │ Queue │ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Adding comments shouldn’t tank your site’s performance:
Page Load Timeline
─────────────────────────────────────────────────►
┌────────────────────────────────────────────────┐
│ STATIC CONTENT │
│ ████████████ │
│ (fast - from CDN) │
└────────────────────────────────────────────────┘
┌────────────────────────────────────────────────┐
│ COMMENT LOADING │
│ ████████████████████████████ │
│ (slower - API + render) │
└────────────────────────────────────────────────┘
┌────────────────────────────────────────────────┐
│ PERCEIVED PERFORMANCE │
│ ████████████──Loading...───████████████████ │
│ Main content ↑ Comments appear │
│ visible Skeleton │
│ loader │
└────────────────────────────────────────────────┘
Key metrics to consider:
Comments are user-generated content that can be irreplaceable:
┌─────────────────────────────────────────────────────────────────┐
│ DATA LIFECYCLE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Creation ──► Storage ──► Backup ──► Export ──► Migration │
│ │ │ │ │ │ │
│ │ │ │ │ │ │
│ Validate Replicate Regular Portable Provider │
│ Sanitize Redundancy Snapshots Formats Independent │
│ │
└─────────────────────────────────────────────────────────────────┘
Questions to answer:
Before building, define your requirements:
| Feature | Priority | Notes |
|---|---|---|
| Post comments | Must Have | Core feature |
| Threaded replies | Should Have | Better UX |
| Edit/Delete own comments | Nice to Have | User control |
| Reactions (likes, etc.) | Nice to Have | Engagement |
| Markdown support | Nice to Have | Rich formatting |
| Email notifications | Should Have | Engagement |
| Admin moderation | Must Have | Content control |
| Requirement | Target | Why |
|---|---|---|
| API Response Time | < 200ms | User experience |
| Availability | 99.9% | Comments always work |
| Storage Cost | < $5/month | Sustainability |
| Spam Block Rate | > 99% | Keep it clean |
| False Positive Rate | < 0.1% | Don’t lose real comments |
Estimate your needs:
┌─────────────────────────────────────────────────────────────────┐
│ TRAFFIC ESTIMATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Monthly Page Views: 10,000 │
│ Pages with Comments: 50 │
│ Avg Comments per Page: 5 │
│ Comment Rate: 1 per 500 views = 20/month │
│ │
│ API Reads (load comments): ~10,000/month │
│ API Writes (new comments): ~20/month │
│ Storage (text): ~50 KB/month │
│ │
│ ───────────────────────────────────────────────────────────── │
│ │
│ 10x Growth Projection: │
│ │
│ Monthly Page Views: 100,000 │
│ API Reads: ~100,000/month │
│ API Writes: ~200/month │
│ Storage: ~500 KB/month (cumulative ~6MB/year) │
│ │
└─────────────────────────────────────────────────────────────────┘
Use this framework to make architectural decisions:
┌─────────────────┐
│ Your Traffic │
│ Level? │
└────────┬────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Low │ │ Medium │ │ High │
│ <1K/mo │ │ 1K-100K │ │ >100K │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
▼ ▼ ▼
Simple/Free Serverless Dedicated
Solutions Functions Infrastructure
│ │ │
▼ ▼ ▼
• GitHub Issues • AWS Lambda • K8s/Docker
• Staticman • Cloudflare • Custom API
• JSON files Workers • DB Cluster
• Vercel Fn
Building a comment system requires solving multiple interconnected problems:
In the next chapter, we’ll explore different architectural approaches in detail, with diagrams showing how each component connects.
Navigation: