Build an envelope budgeting tool with V0 using Next.js, Supabase, and Recharts. You'll get income allocation into spending categories, per-transaction tracking, real-time envelope balances with visual Progress bars, and CSV bank statement import — all in about 1-2 hours without local setup.
What you're building
The envelope budgeting method is one of the most effective personal finance strategies — allocate your income into categories (envelopes) and track spending against each one. When an envelope runs out, you stop spending in that category. Simple, visual, and effective.
V0 generates the budget dashboard, transaction forms, and charts from prompts. Supabase via the Connect panel stores budgets, envelopes, and transactions with database triggers that automatically recalculate envelope balances when transactions change.
The architecture uses Next.js Server Components for the budget overview (fast, server-rendered with real-time data from Supabase), Client Components for interactive elements like transaction forms and chart interactions, and Server Actions for all mutations. A Supabase trigger recalculates the spent amount on each envelope whenever transactions are added, updated, or deleted.
Final result
A complete envelope budgeting app with monthly income allocation, per-category spending tracking, visual progress bars, spending distribution charts, CSV import, and automatic month rollover.
Tech stack
Prerequisites
- A V0 account (Premium plan recommended for multi-feature builds)
- A Supabase project (free tier works — connect via V0's Connect panel)
- A bank statement in CSV format for testing the import feature (optional)
Build steps
Set up the database schema with budget and envelope tables
Create a new V0 project, connect Supabase via the Connect panel, and create the budgets, envelopes, and transactions tables. Add a database trigger that recalculates the spent amount on each envelope whenever transactions change.
1// Paste this prompt into V0's AI chat:2// Build an envelope budgeting tool with Supabase. Create these tables:3// 1. budgets: id (uuid PK), user_id (uuid FK to auth.users), name (text), month (date), total_income (numeric), created_at (timestamptz)4// 2. envelopes: id (uuid PK), budget_id (uuid FK), category (text), allocated (numeric), spent (numeric default 0), color (text)5// 3. transactions: id (uuid PK), envelope_id (uuid FK), user_id (uuid FK), amount (numeric), description (text), date (date), type (text CHECK in 'expense','income','transfer'), created_at (timestamptz)6// Add a database trigger: on transactions INSERT/UPDATE/DELETE, recalculate envelopes.spent as SUM of related expense transactions.7// Add RLS so each user sees only their own budgets, envelopes, and transactions.Pro tip: Use Design Mode (Option+D) to visually adjust envelope Card colors, Progress bar styling, and the dashboard grid layout for free — iterate on the visual design without spending credits.
Expected result: Supabase is connected with all tables created, the trigger auto-recalculates envelope spent amounts, and RLS policies are in place.
Build the monthly budget overview with envelope Cards
Create the main budget page that shows all envelopes for the current month as color-coded Cards with Progress bars. Each Card displays the category name, allocated amount, spent amount, remaining amount, and a visual progress indicator.
1// Paste this prompt into V0's AI chat:2// Build a budget overview page at app/budget/page.tsx (Server Component).3// Requirements:4// - Fetch the current month's budget and envelopes from Supabase5// - Display summary Cards at the top: Total Income, Total Allocated, Total Spent, Remaining6// - Show each envelope as a Card with:7// - Category name and color indicator dot8// - Progress bar (shadcn/ui Progress) showing spent/allocated ratio9// - Text showing "$X of $Y spent" and remaining amount10// - Progress color changes: green (<70%), yellow (70-90%), red (>90%)11// - Add a "New Envelope" Button that opens a Dialog for creating an envelope12// - Add a PieChart (Recharts) showing spending distribution across envelopes13// - Month selector at the top to switch between months14// - If no budget exists for the current month, show a "Create Budget" CTAExpected result: The budget page shows envelope Cards with color-coded Progress bars, summary statistics, and a PieChart for spending distribution.
Create the transaction management system
Build the transaction entry form and history view. Users can add expenses, income, or transfers with category assignment. The database trigger automatically updates the envelope's spent amount.
1'use server'23import { createClient } from '@supabase/supabase-js'4import { revalidatePath } from 'next/cache'56const supabase = createClient(7 process.env.SUPABASE_URL!,8 process.env.SUPABASE_SERVICE_ROLE_KEY!9)1011export async function addTransaction(12 userId: string,13 envelopeId: string,14 amount: number,15 description: string,16 date: string,17 type: 'expense' | 'income' | 'transfer'18) {19 const { error } = await supabase.from('transactions').insert({20 envelope_id: envelopeId,21 user_id: userId,22 amount,23 description,24 date,25 type,26 })2728 if (error) throw new Error(error.message)29 revalidatePath('/budget')30}3132export async function deleteTransaction(transactionId: string) {33 const { error } = await supabase34 .from('transactions')35 .delete()36 .eq('id', transactionId)3738 if (error) throw new Error(error.message)39 revalidatePath('/budget')40}4142export async function rolloverBudget(userId: string, currentBudgetId: string) {43 const { data: currentEnvelopes } = await supabase44 .from('envelopes')45 .select('category, allocated, color')46 .eq('budget_id', currentBudgetId)4748 const nextMonth = new Date()49 nextMonth.setMonth(nextMonth.getMonth() + 1)50 nextMonth.setDate(1)5152 const { data: newBudget } = await supabase.from('budgets').insert({53 user_id: userId,54 name: nextMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' }),55 month: nextMonth.toISOString().split('T')[0],56 total_income: 0,57 }).select().single()5859 if (newBudget && currentEnvelopes) {60 await supabase.from('envelopes').insert(61 currentEnvelopes.map((e) => ({62 budget_id: newBudget.id,63 category: e.category,64 allocated: e.allocated,65 color: e.color,66 }))67 )68 }6970 revalidatePath('/budget')71}Expected result: Users can add and delete transactions. The database trigger recalculates envelope spent amounts automatically. Month rollover clones envelope allocations.
Build the transaction history page with filters
Create a detailed transaction view with filtering by date range, envelope category, and transaction type. Include a sortable Table and the ability to export filtered results.
1// Paste this prompt into V0's AI chat:2// Build a transactions page at app/transactions/page.tsx.3// Requirements:4// - Table of all transactions with columns: Date, Description, Category (from envelope), Amount, Type Badge5// - Date range filter using two DatePicker components (from and to)6// - Select filter for envelope/category7// - Select filter for type (expense, income, transfer)8// - Sortable columns (click header to sort by date, amount)9// - Amount shows negative for expenses (red) and positive for income (green)10// - "Add Transaction" Button opens a Dialog with:11// - Select for envelope (fetches from current month's envelopes)12// - Input for amount with currency formatting13// - Input for description14// - DatePicker for date15// - RadioGroup for type (expense, income, transfer)16// - Use Server Components for initial data fetch with client-side filter stateExpected result: The transactions page shows a filterable, sortable table of all transactions with a form dialog for adding new entries.
Add CSV bank statement import
Create an API route that accepts CSV file uploads, parses them with papaparse, and imports transactions with basic category matching based on description keywords.
1import { NextRequest, NextResponse } from 'next/server'2import { createClient } from '@supabase/supabase-js'3import Papa from 'papaparse'45const supabase = createClient(6 process.env.SUPABASE_URL!,7 process.env.SUPABASE_SERVICE_ROLE_KEY!8)910export async function POST(req: NextRequest) {11 const formData = await req.formData()12 const file = formData.get('file') as File13 const userId = formData.get('user_id') as string14 const budgetId = formData.get('budget_id') as string1516 const text = await file.text()17 const { data: rows } = Papa.parse(text, { header: true, skipEmptyLines: true })1819 const { data: envelopes } = await supabase20 .from('envelopes')21 .select('id, category')22 .eq('budget_id', budgetId)2324 const transactions = (rows as Record<string, string>[]).map((row) => {25 const amount = Math.abs(parseFloat(row.Amount || row.amount || '0'))26 const description = row.Description || row.description || ''27 const date = row.Date || row.date || new Date().toISOString().split('T')[0]28 const type = parseFloat(row.Amount || '0') < 0 ? 'expense' : 'income'2930 const matchedEnvelope = envelopes?.find((e) =>31 description.toLowerCase().includes(e.category.toLowerCase())32 )3334 return {35 envelope_id: matchedEnvelope?.id || envelopes?.[0]?.id,36 user_id: userId,37 amount,38 description,39 date,40 type,41 }42 }).filter((t) => t.envelope_id && t.amount > 0)4344 const { error } = await supabase.from('transactions').insert(transactions)45 if (error) return NextResponse.json({ error: error.message }, { status: 500 })4647 return NextResponse.json({ imported: transactions.length })48}Expected result: Uploading a CSV file parses the transactions, matches them to envelopes by description keywords, and bulk-inserts them into Supabase.
Complete code
1'use server'23import { createClient } from '@supabase/supabase-js'4import { revalidatePath } from 'next/cache'56const supabase = createClient(7 process.env.SUPABASE_URL!,8 process.env.SUPABASE_SERVICE_ROLE_KEY!9)1011export async function addTransaction(12 userId: string,13 envelopeId: string,14 amount: number,15 description: string,16 date: string,17 type: 'expense' | 'income' | 'transfer'18) {19 const { error } = await supabase.from('transactions').insert({20 envelope_id: envelopeId,21 user_id: userId,22 amount,23 description,24 date,25 type,26 })27 if (error) throw new Error(error.message)28 revalidatePath('/budget')29}3031export async function updateEnvelopeAllocation(32 envelopeId: string,33 allocated: number34) {35 const { error } = await supabase36 .from('envelopes')37 .update({ allocated })38 .eq('id', envelopeId)39 if (error) throw new Error(error.message)40 revalidatePath('/budget')41}4243export async function rolloverBudget(44 userId: string,45 currentBudgetId: string46) {47 const { data: envelopes } = await supabase48 .from('envelopes')49 .select('category, allocated, color')50 .eq('budget_id', currentBudgetId)5152 const nextMonth = new Date()53 nextMonth.setMonth(nextMonth.getMonth() + 1)54 nextMonth.setDate(1)5556 const { data: budget } = await supabase57 .from('budgets')58 .insert({59 user_id: userId,60 name: nextMonth.toLocaleDateString('en-US', {61 month: 'long',62 year: 'numeric',63 }),64 month: nextMonth.toISOString().split('T')[0],65 total_income: 0,66 })67 .select()68 .single()6970 if (budget && envelopes) {71 await supabase.from('envelopes').insert(72 envelopes.map((e) => ({73 budget_id: budget.id,74 category: e.category,75 allocated: e.allocated,76 color: e.color,77 }))78 )79 }80 revalidatePath('/budget')81}Customization ideas
Add savings goals
Create a special envelope type for savings goals with target amounts and target dates. Show a countdown to the goal and projected completion based on current saving rate.
Add recurring transactions
Let users mark transactions as recurring (weekly, monthly) and auto-create them using a Supabase Edge Function triggered by pg_cron on a schedule.
Add spending alerts
Send email notifications via Resend when an envelope reaches 80% or 100% of its allocated amount, triggered by the database trigger that recalculates spent amounts.
Add multi-currency support
Add a currency field to transactions and budgets. Use an exchange rate API to convert foreign currency transactions to the base budget currency on import.
Common pitfalls
Pitfall: Calculating envelope balances in JavaScript instead of the database
How to avoid: Use a Supabase database trigger that recalculates envelopes.spent as the SUM of related expense transactions on every INSERT, UPDATE, and DELETE. The database is always the single source of truth.
Pitfall: Not handling month boundaries in date queries
How to avoid: Use proper date range queries: gte('date', firstDayOfMonth) and lte('date', lastDayOfMonth) with correctly calculated boundary dates.
Pitfall: Allowing negative envelope balances without warning
How to avoid: Change the Progress bar color to red when spent exceeds allocated. Show a warning Badge on overdrawn envelopes and optionally block new transactions to that envelope.
Best practices
- Use database triggers to recalculate envelope spent amounts — the database is always the single source of truth
- Use Server Components for the budget overview page to keep Supabase queries server-side and improve performance
- Use Design Mode (Option+D) to visually adjust envelope Card colors, Progress bar styling, and chart themes without spending credits
- Color-code Progress bars based on spending ratio: green (<70%), yellow (70-90%), red (>90%) for instant visual feedback
- Use RLS policies so each user can only see and modify their own budgets, envelopes, and transactions
- Store all monetary values as numeric type in Supabase (not float) to avoid floating-point precision errors
- Use revalidatePath('/budget') in every Server Action that modifies data to keep the dashboard current
- Implement the month rollover as a Server Action rather than a cron job so users control when the new month starts
AI prompts to try
Copy these prompts to build this project faster.
I'm building an envelope budgeting tool with Next.js App Router and Supabase. I need categories (envelopes) with allocated amounts, expense tracking with automatic balance recalculation via database triggers, a monthly overview with charts, and CSV bank statement import. Help me design the Supabase schema and the trigger for recalculating envelope spent amounts.
Build a month rollover Server Action for an envelope budgeting app. The action should: fetch all envelopes from the current month's budget, create a new budget record for next month, clone all envelope categories and allocations to the new budget with spent reset to 0, optionally carry forward unspent amounts as additional allocation. Use Supabase and revalidatePath for cache invalidation.
Frequently asked questions
What is envelope budgeting and how does this app implement it?
Envelope budgeting divides your income into categories (envelopes) with set spending limits. This app creates digital envelopes in Supabase, tracks every transaction against its envelope, and shows visual Progress bars so you can see at a glance how much is left in each category.
How does the automatic balance recalculation work?
A Supabase database trigger fires on every transaction INSERT, UPDATE, or DELETE. It recalculates the envelope's spent column as the SUM of all related expense transactions. This happens at the database level, so balances are always accurate regardless of how transactions are created.
What V0 plan do I need for a budgeting tool?
V0 Premium is recommended because the budgeting tool requires multiple pages (overview, transactions, import), charts, and Server Actions. The free plan's credits may not cover the full build.
Can I import transactions from my bank?
Yes. The CSV import feature accepts standard bank statement exports. It parses the file with papaparse and attempts to match transactions to envelopes based on description keywords. You can manually reassign categories after import.
How do I deploy the budgeting tool?
Click Share then Publish to Production in V0 for instant Vercel deployment. All data is stored in Supabase with RLS policies ensuring each user only sees their own budget data.
Can RapidDev help build a custom budgeting or finance tool?
Yes. RapidDev has built 600+ apps including complex financial tools with bank integrations, automated categorization, and custom reporting. Book a free consultation to discuss your budgeting tool requirements.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation