Comments Demo

3 components dropped into a page

128

Comments (3)

A
Alex 2h ago

Just dropped this in. 3 minutes, done. The RLS alone saved me an afternoon.

S
Sarah 5h ago

IP rate limiting built in?

D
Dev 3h ago

Yep. Configurable: maxRequests, windowMs, per-IP.

M
Mike 1d ago

Best $29 I've spent. Used it in 3 client projects.

500 chars max
app/post/[id]/page.tsx
'use client';
import { CommentList, CommentForm, LikeButton } from 'nextjs-supabase-comments';

export default function PostPage() {
  const [refresh, setRefresh] = useState(0);

  return (
    <div>
      {/* 1. Like button — optimistic UI */}
      <LikeButton postId={post.id} userId={user.id} />

      {/* 2. Threaded comments */}
      <CommentList postId={post.id} refreshKey={refresh} />

      {/* 3. Comment form */}
      <CommentForm
        postId={post.id}
        userId={user.id}
        username={user.name}
        onCommentPosted{() => setRefresh(k => k + 1)}
      />
    </div>
  );
}
app/api/comments/route.ts
import { createCommentsHandler } from 'nextjs-supabase-comments';

const handler = createCommentsHandler({
  maxLength: 500,
  blockedKeywords: ['spam'],
});

export const GET = handler.GET;
export const POST = handler.POST;
9:41 Post ●●●
U
username
128 likes
A
Alex 2h

Just dropped this in. 3 minutes!

S
Sarah 5h

Rate limiting built in? Nice.

supabase/migrations/00001_comments_likes.sql
-- comments table (threaded)
CREATE TABLE comments (
  id         UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  post_id    TEXT NOT NULL,
  user_id    TEXT NOT NULL,
  username   TEXT NOT NULL,
  parent_id  UUID REFERENCES comments(id),
  content    TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- likes table (unique per user)
CREATE TABLE likes (
  id         UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  post_id    TEXT NOT NULL,
  user_id    TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now(),
  UNIQUE(post_id, user_id)
);

-- RLS policies included