Skip to main content
RapidDev - Software Development Agency
how-to-build-v030-60 minutes

How to Build Reviews & ratings with V0

Build a star rating and review system with V0 using Next.js and Supabase that adds user reviews with 1-5 star ratings, helpful votes, photo uploads, and basic moderation to any product or service app. Features aggregate stats via database triggers — all in about 30-60 minutes.

What you'll build

  • Star rating input component built with Lucide Star icons in a 'use client' wrapper
  • Review submission form with star rating, title, body text, and optional photo upload
  • Reviews list sorted by helpful/recent with shadcn/ui Cards, Avatars, and Badges
  • Helpful vote system with optimistic updates and duplicate vote prevention
  • Aggregate review stats maintained by Supabase database triggers
  • Admin moderation queue with approve/reject/flag actions
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read30-60 minutesV0 FreeApril 2026RapidDev Engineering Team
TL;DR

Build a star rating and review system with V0 using Next.js and Supabase that adds user reviews with 1-5 star ratings, helpful votes, photo uploads, and basic moderation to any product or service app. Features aggregate stats via database triggers — all in about 30-60 minutes.

What you're building

Reviews and ratings build trust. Whether you are selling products, listing services, or running a marketplace, user-generated reviews with star ratings directly impact purchase decisions. A good review system needs to be easy to submit, hard to spam, and fast to display aggregate scores.

V0 generates the review form, star rating component, review list, and moderation queue from prompts. The key architectural decision is using Supabase database triggers to maintain aggregate stats (average rating, total reviews, rating distribution) so you never need expensive COUNT queries on the reviews table.

The architecture uses Next.js App Router with Server Components for the reviews list (SEO-friendly), a client component for the interactive star rating, Server Actions for all mutations, Supabase triggers for maintaining aggregate stats, and Supabase Storage for review photos.

Final result

A review and rating system with 5-star ratings, text reviews with photos, helpful vote buttons, verified purchase badges, admin moderation, and always-current aggregate statistics.

Tech stack

V0AI Code Generator
Next.jsFull-Stack Framework
Tailwind CSSStyling
shadcn/uiComponent Library
SupabaseDatabase

Prerequisites

  • A V0 account (free tier works for this project)
  • A Supabase project (free tier works — connect via V0's Connect panel)
  • A product, service, or item you want users to review

Build steps

1

Set up the project and reviews schema with triggers

Open V0 and create a new project. Use the Connect panel to add Supabase. Create the schema for reviews, images, helpful votes, and aggregate stats. Add a database trigger to auto-update stats on every review insert or update.

prompt.txt
1// Paste this prompt into V0's AI chat:
2// Build a reviews and ratings system. Create a Supabase schema with:
3// 1. reviews: id (uuid PK), author_id (uuid FK), item_id (uuid FK), item_type (text check product/service/business), rating (integer check 1-5), title (text), body (text), is_verified_purchase (boolean default false), status (text check pending/approved/rejected/flagged), created_at (timestamptz), updated_at (timestamptz)
4// 2. review_images: id (uuid PK), review_id (uuid FK), image_url (text), position (integer)
5// 3. helpful_votes: id (uuid PK), review_id (uuid FK), user_id (uuid FK), created_at (timestamptz) with unique constraint on (review_id, user_id)
6// 4. review_stats: item_id (uuid PK), average_rating (numeric), total_reviews (integer), rating_distribution (jsonb), updated_at (timestamptz)
7// Create a database trigger on reviews INSERT/UPDATE that recalculates review_stats for the affected item_id.
8// RLS: anyone can SELECT approved reviews, authenticated users can INSERT, only author/admin can UPDATE.
9// Generate SQL migration and TypeScript types.

Pro tip: The database trigger keeps review_stats always current without expensive COUNT queries — this is critical for performance as your review count grows.

Expected result: Supabase is connected with reviews, images, votes, and stats tables. A database trigger automatically recalculates aggregate stats whenever a review is added or updated.

2

Build the star rating component and review form

Create a reusable star rating input component and the review submission form. The star component uses Lucide Star icons with hover and click states. The form includes rating, title, body, and photo upload.

components/star-rating.tsx
1'use client'
2
3import { useState } from 'react'
4import { Star } from 'lucide-react'
5import { cn } from '@/lib/utils'
6
7export function StarRating({
8 value,
9 onChange,
10 readonly = false,
11}: {
12 value: number
13 onChange?: (rating: number) => void
14 readonly?: boolean
15}) {
16 const [hover, setHover] = useState(0)
17
18 return (
19 <div className="flex gap-1">
20 {[1, 2, 3, 4, 5].map((star) => (
21 <Star
22 key={star}
23 className={cn(
24 'w-6 h-6 transition-colors',
25 (hover || value) >= star
26 ? 'fill-yellow-400 text-yellow-400'
27 : 'text-muted-foreground',
28 !readonly && 'cursor-pointer'
29 )}
30 onMouseEnter={() => !readonly && setHover(star)}
31 onMouseLeave={() => !readonly && setHover(0)}
32 onClick={() => onChange?.(star)}
33 />
34 ))}
35 </div>
36 )
37}

Expected result: A reusable star rating component with hover and click states. Stars fill with yellow on hover and lock on click. Can be used as input (interactive) or display (readonly).

3

Create the reviews list with helpful votes

Build the reviews display for an item page. Reviews are sorted by most helpful or most recent, with aggregate stats at the top showing average rating and distribution breakdown.

prompt.txt
1// Paste this prompt into V0's AI chat:
2// Build a reviews section for app/items/[id]/reviews/page.tsx.
3// Requirements:
4// - Top section: aggregate stats from review_stats table
5// - Large average rating number with StarRating (readonly), total review count
6// - Rating distribution bars: 5 rows (5 stars to 1 star), each with a Progress bar and count
7// - Sort controls: DropdownMenu with options: Most Helpful, Newest, Highest Rated, Lowest Rated
8// - Review list: shadcn/ui Card for each review showing:
9// - Avatar with author name, StarRating (readonly), date
10// - Badge for "Verified Purchase" if is_verified_purchase
11// - Review title (bold), body text
12// - Review photos as small image thumbnails (if any)
13// - "Helpful" Button with count — clicking calls Server Action markHelpful() with optimistic update
14// - "Write a Review" Button at top opens the review form Dialog
15// - Use Server Components for data fetching, 'use client' for star rating and helpful vote
16// - Server Actions: submitReview(), markHelpful()

Pro tip: Use V0's Design Mode (Option+D) to visually adjust the star rating colors, review Card spacing, and image gallery layout without spending credits.

Expected result: A reviews section showing aggregate stats with distribution bars, sortable review Cards with star ratings, helpful vote buttons, and verified purchase Badges.

4

Add the admin moderation queue

Build an admin page for moderating reviews. New reviews start with status 'pending' and need approval before they appear publicly. Admins can approve, reject, or flag reviews.

prompt.txt
1// Paste this prompt into V0's AI chat:
2// Build a review moderation page at app/reviews/page.tsx.
3// Requirements:
4// - Protected by admin auth
5// - Tabs: Pending, Approved, Rejected, Flagged
6// - Table of reviews showing: item name, author, rating (stars), title, body preview (50 chars), status Badge, date
7// - Each row has action Buttons:
8// - Approve (green): sets status to 'approved', triggers stats recalculation
9// - Reject (red): opens AlertDialog for rejection reason, sets status to 'rejected'
10// - Flag (yellow): sets status to 'flagged' for further review
11// - Bulk action: Checkbox selection with bulk approve/reject Buttons
12// - Server Actions: moderateReview() that updates status and logs the action
13// - Server Components for data fetching
14// - Use shadcn/ui Table, Badge, Button, AlertDialog, Checkbox, Tabs

Expected result: An admin moderation queue with tabs for review statuses, a Table of reviews with approve/reject/flag actions, and bulk moderation capabilities.

Complete code

app/actions/reviews.ts
1'use server'
2
3import { createClient } from '@/lib/supabase/server'
4import { revalidatePath } from 'next/cache'
5
6export async function submitReview(formData: FormData) {
7 const supabase = await createClient()
8 const { data: { user } } = await supabase.auth.getUser()
9 if (!user) throw new Error('Must be logged in')
10
11 const { data: review } = await supabase
12 .from('reviews')
13 .insert({
14 author_id: user.id,
15 item_id: formData.get('item_id') as string,
16 item_type: formData.get('item_type') as string,
17 rating: parseInt(formData.get('rating') as string),
18 title: formData.get('title') as string,
19 body: formData.get('body') as string,
20 status: 'pending',
21 })
22 .select()
23 .single()
24
25 if (!review) throw new Error('Failed to submit review')
26
27 const itemId = formData.get('item_id') as string
28 revalidatePath(`/items/${itemId}/reviews`)
29 return review
30}
31
32export async function markHelpful(reviewId: string) {
33 const supabase = await createClient()
34 const { data: { user } } = await supabase.auth.getUser()
35 if (!user) throw new Error('Must be logged in')
36
37 const { error } = await supabase
38 .from('helpful_votes')
39 .insert({ review_id: reviewId, user_id: user.id })
40
41 if (error && error.code !== '23505') {
42 throw new Error(error.message)
43 }
44}
45
46export async function moderateReview(
47 reviewId: string,
48 status: 'approved' | 'rejected' | 'flagged'
49) {
50 const supabase = await createClient()
51
52 await supabase
53 .from('reviews')
54 .update({ status, updated_at: new Date().toISOString() })
55 .eq('id', reviewId)
56
57 revalidatePath('/reviews')
58}

Customization ideas

Add review responses from owners

Let business or product owners reply to reviews publicly, showing a threaded response below the original review.

Build spam detection

Use OpenAI to automatically flag suspicious reviews based on content patterns — fake enthusiasm, copied text, or review bombing within short timeframes.

Add review analytics

Build a dashboard showing review trends over time, sentiment analysis, and keyword extraction using Recharts visualizations.

Implement review incentives

Send automated email reminders asking verified purchasers to leave reviews, with optional reward points or discount codes for completion.

Common pitfalls

Pitfall: Computing average ratings with a COUNT query on every page load

How to avoid: Use a Supabase database trigger on reviews INSERT/UPDATE that recalculates review_stats for the affected item_id. The display page reads from the pre-computed stats table.

Pitfall: Allowing the star rating component to render server-side

How to avoid: Mark the star rating component with 'use client'. When displaying reviews, use a readonly version of the same component.

Pitfall: Not handling the 23505 duplicate key error for helpful votes

How to avoid: Catch the 23505 error code in the markHelpful Server Action and silently ignore it — the vote is already recorded.

Best practices

  • Use Supabase database triggers to maintain aggregate review_stats instead of computing averages on every page load
  • Use V0's Design Mode (Option+D) to visually adjust star colors, review Card spacing, and image thumbnails for free
  • Store review images in a Supabase Storage public bucket for permanent, SEO-friendly URLs
  • Handle the Supabase 23505 duplicate key error gracefully for helpful vote deduplication
  • Use Server Components for the reviews list to optimize SEO — reviews are valuable search content
  • Start reviews with status 'pending' and require admin approval to prevent spam from appearing publicly

AI prompts to try

Copy these prompts to build this project faster.

ChatGPT Prompt

I'm building a reviews system with Next.js App Router and Supabase. Write a PostgreSQL trigger function that fires on INSERT or UPDATE on the reviews table. It should recalculate the review_stats row for the affected item_id: compute average_rating, total_reviews (only counting approved reviews), and rating_distribution as a JSONB object mapping each star level (1-5) to its count. Include the CREATE TRIGGER statement.

Build Prompt

Create a review aggregate stats component. Accept review_stats data (average_rating, total_reviews, rating_distribution). Display the average as a large number with readonly StarRating, total count, and 5 rating distribution rows. Each row shows '5 stars' label, a shadcn/ui Progress bar proportional to that rating's percentage, and the count number. Use Server Components for data fetching.

Frequently asked questions

Can I build this on V0's free tier?

Yes. The free tier provides enough credits to generate the star rating component, review form, reviews list, and moderation page. Supabase free tier handles the database and image storage.

How do aggregate stats stay up to date?

A Supabase database trigger fires on every review INSERT or UPDATE. It recalculates the average_rating, total_reviews, and rating_distribution for the affected item and updates the review_stats table. The display page reads from this pre-computed table.

How do I prevent fake reviews?

The build includes three layers: authentication (only logged-in users can review), moderation queue (admin approves before public display), and verified purchase badges. You can add AI-based spam detection as a customization.

Can I use this for any type of item (products, services, businesses)?

Yes. The item_type field (product/service/business) makes the system generic. Reviews are linked to any item via item_id, so you can attach reviews to products, services, courses, or any entity in your app.

How do I deploy the reviews system?

Click Share then Publish to Production in V0. Review pages are server-rendered for SEO. Supabase credentials are auto-configured from the Connect panel.

Can RapidDev help build a custom reviews platform?

Yes. RapidDev has built 600+ apps including review platforms with AI moderation, sentiment analysis, and review incentive systems. Book a free consultation to discuss your requirements.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help building your app?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.