Skip to main content
RapidDev - Software Development Agency

How to Build Budgeting tool with V0

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'll build

  • Monthly budget overview with envelope Cards showing allocated vs spent amounts using shadcn/ui Progress
  • Transaction entry form with Dialog, amount Input, and envelope Select for category assignment
  • Spending distribution PieChart using Recharts for visual budget breakdown
  • CSV bank statement import via API route with papaparse for automatic transaction categorization
  • Month rollover logic that clones envelope allocations to the next month via Server Action
  • Date range filtering with DatePicker and department-level transaction Table with sorting
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate10 min read1-2 hoursV0 Premium or higherApril 2026RapidDev Engineering Team
TL;DR

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

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

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

1

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.

prompt.txt
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.

2

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.

prompt.txt
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 Supabase
5// - Display summary Cards at the top: Total Income, Total Allocated, Total Spent, Remaining
6// - Show each envelope as a Card with:
7// - Category name and color indicator dot
8// - Progress bar (shadcn/ui Progress) showing spent/allocated ratio
9// - Text showing "$X of $Y spent" and remaining amount
10// - Progress color changes: green (<70%), yellow (70-90%), red (>90%)
11// - Add a "New Envelope" Button that opens a Dialog for creating an envelope
12// - Add a PieChart (Recharts) showing spending distribution across envelopes
13// - Month selector at the top to switch between months
14// - If no budget exists for the current month, show a "Create Budget" CTA

Expected result: The budget page shows envelope Cards with color-coded Progress bars, summary statistics, and a PieChart for spending distribution.

3

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.

app/actions/budget.ts
1'use server'
2
3import { createClient } from '@supabase/supabase-js'
4import { revalidatePath } from 'next/cache'
5
6const supabase = createClient(
7 process.env.SUPABASE_URL!,
8 process.env.SUPABASE_SERVICE_ROLE_KEY!
9)
10
11export 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
28 if (error) throw new Error(error.message)
29 revalidatePath('/budget')
30}
31
32export async function deleteTransaction(transactionId: string) {
33 const { error } = await supabase
34 .from('transactions')
35 .delete()
36 .eq('id', transactionId)
37
38 if (error) throw new Error(error.message)
39 revalidatePath('/budget')
40}
41
42export async function rolloverBudget(userId: string, currentBudgetId: string) {
43 const { data: currentEnvelopes } = await supabase
44 .from('envelopes')
45 .select('category, allocated, color')
46 .eq('budget_id', currentBudgetId)
47
48 const nextMonth = new Date()
49 nextMonth.setMonth(nextMonth.getMonth() + 1)
50 nextMonth.setDate(1)
51
52 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()
58
59 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 }
69
70 revalidatePath('/budget')
71}

Expected result: Users can add and delete transactions. The database trigger recalculates envelope spent amounts automatically. Month rollover clones envelope allocations.

4

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.

prompt.txt
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 Badge
5// - Date range filter using two DatePicker components (from and to)
6// - Select filter for envelope/category
7// - 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 formatting
13// - Input for description
14// - DatePicker for date
15// - RadioGroup for type (expense, income, transfer)
16// - Use Server Components for initial data fetch with client-side filter state

Expected result: The transactions page shows a filterable, sortable table of all transactions with a form dialog for adding new entries.

5

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.

app/api/import/route.ts
1import { NextRequest, NextResponse } from 'next/server'
2import { createClient } from '@supabase/supabase-js'
3import Papa from 'papaparse'
4
5const supabase = createClient(
6 process.env.SUPABASE_URL!,
7 process.env.SUPABASE_SERVICE_ROLE_KEY!
8)
9
10export async function POST(req: NextRequest) {
11 const formData = await req.formData()
12 const file = formData.get('file') as File
13 const userId = formData.get('user_id') as string
14 const budgetId = formData.get('budget_id') as string
15
16 const text = await file.text()
17 const { data: rows } = Papa.parse(text, { header: true, skipEmptyLines: true })
18
19 const { data: envelopes } = await supabase
20 .from('envelopes')
21 .select('id, category')
22 .eq('budget_id', budgetId)
23
24 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'
29
30 const matchedEnvelope = envelopes?.find((e) =>
31 description.toLowerCase().includes(e.category.toLowerCase())
32 )
33
34 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)
43
44 const { error } = await supabase.from('transactions').insert(transactions)
45 if (error) return NextResponse.json({ error: error.message }, { status: 500 })
46
47 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

app/actions/budget.ts
1'use server'
2
3import { createClient } from '@supabase/supabase-js'
4import { revalidatePath } from 'next/cache'
5
6const supabase = createClient(
7 process.env.SUPABASE_URL!,
8 process.env.SUPABASE_SERVICE_ROLE_KEY!
9)
10
11export 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}
30
31export async function updateEnvelopeAllocation(
32 envelopeId: string,
33 allocated: number
34) {
35 const { error } = await supabase
36 .from('envelopes')
37 .update({ allocated })
38 .eq('id', envelopeId)
39 if (error) throw new Error(error.message)
40 revalidatePath('/budget')
41}
42
43export async function rolloverBudget(
44 userId: string,
45 currentBudgetId: string
46) {
47 const { data: envelopes } = await supabase
48 .from('envelopes')
49 .select('category, allocated, color')
50 .eq('budget_id', currentBudgetId)
51
52 const nextMonth = new Date()
53 nextMonth.setMonth(nextMonth.getMonth() + 1)
54 nextMonth.setDate(1)
55
56 const { data: budget } = await supabase
57 .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()
69
70 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.

ChatGPT Prompt

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 Prompt

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.

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.