Implementing Comment Functionality: Linking Data in Next.js
Learn how to create a comment model, build a submission form, and link user feedback to specific blog posts using Prisma and Next.js.
Previously in this course, we covered fetching data from the database in next.js server components. Now that we can display posts, it's time to let your readers participate by adding a comments section.
To build a functional comments system, we need to bridge the gap between our frontend forms and our database. We'll start by defining the relationship between posts and comments, then create the UI to capture that data.
Defining the Comment Model
In relational databases, we use foreign keys to establish relationships between tables. Just as we discussed when implementing foreign keys: connecting tables in postgresql, we need to tell Prisma that every comment "belongs to" a specific post.
Open your prisma/schema.prisma file and add the Comment model:
PRISMAmodel Comment { id String @id @default(uuid()) content String author String createdAt DateTime @default(now()) // Link to the Post model postId String post Post @relation(fields: [postId], references: [id], onDelete: Cascade) } model Post { id String @id @default(uuid()) title String // Add this field to your existing Post model comments Comment[] }
By adding comments Comment[] to your Post model, you enable Prisma to fetch comments directly through the post object. After saving this file, run npx prisma migrate dev --name add_comment_model to update your database.
Building the Comment Form
Now that our database schema supports comments, we need a way to capture user input. We'll build a simple Server Component that renders a form. Since this form needs to interact with our backend, we’ll use the introduction to server actions: handling forms in next.js patterns we've already established.
Create a file at components/CommentForm.tsx:
TSXexport default function CommentForm({ postId }: { postId: string }) { return ( <form action="/api/submit-comment" className="mt-8"> <input type="hidden" name="postId" value={postId} /> <div className="flex flex-col gap-4"> <input name="author" placeholder="Your name" className="border p-2 rounded" required /> <textarea name="content" placeholder="Leave a comment..." className="border p-2 rounded" required /> <button type="submit" className="bg-blue-600 text-white p-2 rounded"> Post Comment </button> </div> </form> ); }
Linking Comments to Posts
The final step is to display these comments on your dynamic blog page. In your app/blog/[slug]/page.tsx, you can now query the comments alongside the post:
TSX// Inside your Page component const post = await prisma.post.findUnique({ where: { slug: params.slug }, include: { comments: true } // Fetch linked comments }); return ( <div> <h1>{post.title}</h1> {/* Display post content */} <section> <h2>Comments</h2> {post.comments.map(comment => ( <p key={comment.id}>{comment.content} - {comment.author}</p> ))} <CommentForm postId={post.id} /> </section> </div> );
Practice Exercise
Your task is to add a "Date" field to the comment display.
- Modify the
CommentFormto include a hidden timestamp or just rely on the databasecreatedAtfield. - In your
[slug]/page.tsx, use the JavaScript.toLocaleDateString()method to format thecomment.createdAtfield so it displays cleanly for the user.
Common Pitfalls
- Forgetting to include the relation: If you forget
include: { comments: true }in your Prisma query, thecommentsarray will be undefined on the post object, leading to runtime errors. - Missing
onDelete: Cascade: If you delete a post but the comments remain in the database, you'll end up with "orphaned" records that can cause foreign key constraint violations later. Always define your cascade strategy in the schema. - Client vs Server: Remember that the
CommentFormitself can be a Client Component if you need to manage local form state (like clearing the input after submission), but the action that writes to the database must remain a Server Action.
FAQ
Why use onDelete: Cascade?
It automates cleanup. When a parent record (the post) is deleted, the database automatically removes all associated child records (the comments), keeping your data integrity intact.
Can I nest comments?
Yes, you can add a parentId field to the Comment model that references another Comment. This allows for threaded replies, similar to how WP_Comment_Query: How WordPress Fetches Comments and Threaded Replies handles hierarchy.
Recap
We've successfully extended our database schema to support comments, established a relational link between posts and comments, and built a UI form to accept user submissions. By leveraging Prisma's include syntax, we've made the data flow from the database to the component seamless.
Up next: We'll flesh out the CRUD operations for these comments, focusing on how to update and delete them securely.
Work with me

React & Next.js Dashboard / Admin UI Development
A clean, data-rich dashboard UI in React or Next.js — charts, tables, and real-time data that your users will actually enjoy using.

Next.js Full-Stack Web App Development
A fast, SEO-ready full-stack web app built with Next.js 16 — from idea to deployed product, by an engineer who ships to production.


