Zero-Based Budgeting in Beancount: How I Allocate Every Dollar Before It's Spent

After three years of tracking expenses in Beancount, I realized I was doing it backwards. I was recording where money went after it was spent, then feeling bad about the results. Sound familiar?

Six months ago I switched to zero-based budgeting in Beancount and it completely changed my relationship with money. Every dollar gets a job before I spend it. Here’s exactly how I set it up.

What Zero-Based Budgeting Actually Means

The concept is simple: your income minus your allocated budget should equal zero. Not because you spend everything, but because every dollar is assigned a purpose - including savings, investments, and debt payments.

Income:        $7,200
- Housing:     $1,800
- Food:          $600
- Transport:     $400
- Insurance:     $350
- Utilities:     $200
- Investing:   $2,500
- Emergency:     $500
- Fun:           $400
- Clothing:      $150
- Subscriptions: $100
- Buffer:        $200
= Remaining:       $0

The key insight: saving and investing are budget categories, not leftovers.

The Account Structure

Here’s the Beancount structure I use. The trick is treating budget categories as virtual equity accounts that represent the purpose of your money:

; === INCOME ===
2025-01-01 open Income:Salary USD
2025-01-01 open Income:Side USD

; === REAL ACCOUNTS (where money physically lives) ===
2025-01-01 open Assets:Checking:Main USD
2025-01-01 open Assets:Savings:Emergency USD
2025-01-01 open Assets:Savings:Vacation USD
2025-01-01 open Assets:Investments:Brokerage USD

; === BUDGET CATEGORIES (where money is assigned) ===
; These track spending against allocated amounts
2025-01-01 open Expenses:Housing:Rent USD
2025-01-01 open Expenses:Housing:Utilities USD
2025-01-01 open Expenses:Food:Groceries USD
2025-01-01 open Expenses:Food:DiningOut USD
2025-01-01 open Expenses:Transport:Gas USD
2025-01-01 open Expenses:Transport:Insurance USD
2025-01-01 open Expenses:Personal:Clothing USD
2025-01-01 open Expenses:Personal:Fun USD
2025-01-01 open Expenses:Subscriptions USD
2025-01-01 open Expenses:Health:Insurance USD
2025-01-01 open Expenses:Health:Copays USD

Monthly Budget Allocation

At the start of each month, I record my budget as a note directive. This becomes my reference for the month:

2025-02-01 note Assets:Checking:Main "
=== FEBRUARY 2025 ZERO-BASED BUDGET ===

INCOME: $7,200 (salary) + $400 (side hustle) = $7,600

NEEDS (50%):
  Housing:Rent                    $1,800
  Housing:Utilities                 $200
  Food:Groceries                    $500
  Transport:Gas                     $200
  Transport:Insurance               $150
  Health:Insurance                  $350
  Subscriptions (essential)         $60
  NEEDS TOTAL:                   $3,260

WANTS (20%):
  Food:DiningOut                    $200
  Personal:Fun                      $400
  Personal:Clothing                 $150
  Subscriptions (entertainment)     $40
  Buffer (unexpected)               $200
  WANTS TOTAL:                      $990

SAVINGS & INVESTING (30%):
  Investments:Brokerage           $2,500
  Savings:Emergency                 $500
  Savings:Vacation                  $350
  SAVINGS TOTAL:                  $3,350

TOTAL ALLOCATED: $7,600
REMAINING: $0

STATUS: Every dollar has a job.
"

Tracking Against Budget

As I spend during the month, each transaction falls into its budget category naturally through the expense accounts:

; Week 1 spending
2025-02-03 * "Safeway" "Weekly groceries"
  Expenses:Food:Groceries             87.42 USD
  Assets:Checking:Main               -87.42 USD

2025-02-05 * "Shell" "Gas for commute"
  Expenses:Transport:Gas              45.00 USD
  Assets:Checking:Main               -45.00 USD

2025-02-07 * "Steam" "Game purchase - budgeted fun money"
  Expenses:Personal:Fun               29.99 USD
  Assets:Checking:Main               -29.99 USD

The Monthly Review Query

This is the query I run mid-month and end-of-month to see how I’m doing against budget:

; Budget vs Actual for current month
SELECT
  account,
  sum(position) as actual
WHERE
  account ~ 'Expenses'
  AND year = 2025
  AND month = 2
GROUP BY account
ORDER BY sum(position) DESC

Then I compare against my note directive. If groceries are at $380 by mid-month against a $500 budget, I know I’m on track. If dining out is already at $180 against $200, I need to cool it for the rest of the month.

The “Pay Yourself First” Automation

The most important part of ZBB: investments and savings happen on the 1st, not the 31st.

; First of the month - non-negotiable
2025-02-01 * "Vanguard" "Monthly investment - automatic"
  Assets:Investments:Brokerage      2,500.00 USD
  Assets:Checking:Main             -2,500.00 USD

2025-02-01 * "Transfer" "Emergency fund contribution"
  Assets:Savings:Emergency            500.00 USD
  Assets:Checking:Main               -500.00 USD

2025-02-01 * "Transfer" "Vacation sinking fund"
  Assets:Savings:Vacation             350.00 USD
  Assets:Checking:Main               -350.00 USD

By moving these first, I can only overspend what’s left. That’s the whole point.

What Changed for Me

Before ZBB, I was saving about 20% of my income and felt like I was doing okay. After implementing ZBB, I bumped to 33% without feeling more restricted. The difference was intentionality - I stopped spending $200/month on random Amazon purchases because I could see exactly what that money was supposed to be doing.

My FIRE projections moved up by nearly 3 years just from this shift. Not from earning more, but from being deliberate about where every dollar goes.

Questions for the Community

  1. How do you handle variable income months? My side hustle income fluctuates $200-800/month. Right now I budget conservatively and treat anything extra as bonus investment money.

  2. Envelope rollover: If I underspend on groceries by $50 this month, do you roll that into next month’s grocery budget or reallocate it? I’ve been sending surpluses to investments.

  3. Anyone using fava-envelope? I’ve been doing this manually with notes and queries. Is the plugin worth setting up?

  4. Joint budgets: For those budgeting with a partner, how do you structure the accounts? My partner isn’t a Beancount user (understatement) so I need to keep it simple enough to discuss.

The biggest thing ZBB taught me: you don’t need to earn more to save more. You need to decide where your money goes before it decides for you.

Okay this is exactly what I needed to see. I’ve been using Beancount for about four months now and I’ve basically been doing “expense archaeology” - recording where money went after it’s already gone. Your post made me realize that’s only half the picture.

My Current (Broken) Workflow

Right now I import my bank CSV at the end of the month, categorize everything, and then look at the totals and go “huh, that’s a lot of takeout.” But nothing changes because by then the money is already spent.

; This is basically my entire workflow right now:
2025-01-28 * "Uber Eats" "Late night ramen"
  Expenses:Food:DiningOut            23.50 USD
  Assets:Checking                   -23.50 USD
  ; Me at month-end: "wow I spent $380 on dining out"
  ; Also me next month: *orders Uber Eats*

Dumb Questions Incoming

  1. Where do you physically write the budget? You’re using note directives, but is there a way to make Fava actually show budget vs. actual in a dashboard? Or are you just manually comparing?

  2. When you go over budget in a category, what do you actually do in Beancount? Like if I spend $550 on groceries but budgeted $500, do I just… record it normally and note that I went over? Or do you move money from another category?

  3. The “pay yourself first” transfers - these are real bank transfers to separate accounts, right? Not just virtual allocations? I ask because I only have one checking account and one savings account. I don’t have separate accounts for vacation vs emergency vs investments.

  4. How long did it take you to get the categories right? I feel like I’d either have 5 categories (too broad to be useful) or 50 categories (too granular to maintain). You seem to have found a sweet spot.

What I’m Tempted to Try

Based on your post, I’m thinking about something like this for my situation:

; My income is simpler - just salary
; Take-home: ~$5,200/month

2025-03-01 note Assets:Checking "
=== MARCH 2025 BUDGET ATTEMPT #1 ===

INCOME: $5,200

FIXED:
  Rent:                    $1,450
  Utilities:                 $120
  Phone:                      $45
  Subscriptions:              $65
  Student loans:             $350
  FIXED TOTAL:             $2,030

FLEXIBLE:
  Groceries:                 $400
  Dining out:                $150
  Transport (bus pass):       $100
  Personal/fun:              $200
  Clothing:                   $75
  FLEXIBLE TOTAL:            $925

SAVINGS:
  Emergency fund:            $500
  Roth IRA:                  $500
  General savings:           $245
  SAVINGS TOTAL:           $1,245

BUFFER (stuff I forget):     $200
  (Pet costs, gifts, random things)

UNALLOCATED: $800
  ... wait, that doesn't add up.
  Let me recalculate.
"

See, I already messed up the math. This is why I code for a living and not accounting. But at least with Beancount I can version control my budget attempts and see how they evolve over time, right?

I think the hardest part for me is going to be checking the budget before spending. Like, am I supposed to open Fava on my phone before I buy coffee? How do you make the checking-before-spending part practical in daily life?

Really appreciate you sharing this, Fred. The “savings isn’t the leftover, it’s a budget line” mindset shift is clicking for me.

Great post, Fred. I want to add some perspective from someone who went through a few iterations of budgeting in Beancount before finding what works.

My Evolution

Year 1: Just tracked expenses. Same as Sarah described - expense archaeology.

Year 2: Tried full ZBB with 40+ categories. Burned out in 3 months. Too much friction.

Year 3: Found my sweet spot - what I call “guided tracking with guardrails.” Not pure ZBB, but close enough to change behavior without the overhead.

The “Start Simple” Budget Structure

For anyone getting started, I’d recommend fewer categories than Fred uses. You can always add more later, but you can’t easily merge categories that have a year of data.

; The beginner-friendly ZBB structure
; Only 6 budget categories to start

2025-01-01 note Equity:Budget "
=== SIMPLIFIED ZERO-BASED BUDGET ===

I use only 6 categories because I can hold 6 numbers
in my head while standing in a checkout line.

1. BILLS (fixed monthly)     - everything auto-paid
2. FOOD (groceries + dining) - one combined number
3. TRANSPORT                 - gas, parking, transit
4. FUN (all discretionary)   - entertainment, hobbies, etc
5. SAVINGS                   - pay yourself first
6. BUFFER                    - everything else

That's it. No splitting groceries from dining out.
No separating clothing from personal care.
Not yet.

Once this becomes second nature (3-6 months),
THEN split categories based on what you actually
want more visibility into.
"

Answering Sarah’s Question: Checking Before Spending

This is the practical challenge with ZBB in Beancount. YNAB has a mobile app that shows your envelope balances in real-time. We don’t have that.

Here’s what I actually do:

2025-02-01 note Expenses "
=== MY PRACTICAL ZBB WORKFLOW ===

WEEKLY (Sunday evening, 10 minutes):
  1. Open Fava
  2. Enter any cash/receipt transactions from the week
  3. Run budget-vs-actual query
  4. Update my phone note with remaining balances

THE PHONE NOTE (updated weekly):
  Food: $320 left of $600
  Fun: $250 left of $400
  Transport: $155 left of $200
  Buffer: $200 left of $200

  This is my 'check before spending' system.
  It's not real-time, but it's close enough.
  I glance at it before any purchase over $30.

MONTHLY (1st of month, 30 minutes):
  1. Reconcile all accounts
  2. Review budget vs actual
  3. Set next month's budget (copy and adjust)
  4. Move savings/investment money first
"

The phone note trick is low-tech but it works. I tried syncing Fava to mobile and it was more hassle than it was worth.

On the Rollover Question

Fred, I’ve tried both approaches and here’s my take:

Don’t roll over. Reset each month. Here’s why:

If you underspend groceries by $50, that $50 goes into next month’s budget as “bonus” money you can allocate anywhere. Maybe you put it toward your vacation fund. Maybe you increase your fun budget that month because you have a birthday dinner.

The reset forces you to make an active decision about surplus money every month instead of letting it quietly accumulate in a category. That monthly reallocation conversation (even if it’s just with yourself) is where the behavioral change happens.

; End of month surplus example
2025-02-28 note Assets:Checking:Main "
=== FEBRUARY SURPLUS ALLOCATION ===

Categories under budget:
  Food:        -$47 (ate more at home this month)
  Transport:   -$23 (worked from home more)
  Clothing:    -$80 (nothing needed)
  Buffer:     -$130 (no surprises this month)

Total surplus: $280

Reallocation decision:
  $200 -> Additional investment (Vanguard)
  $80  -> Add to March fun budget (concert tickets)

This is the ZBB superpower: you DECIDE where
surplus goes instead of it disappearing into
general spending.
"

One Warning About Over-Engineering

I’ve seen people in this community build elaborate budgeting plugins, custom Fava extensions, and Python scripts to automate every aspect of ZBB. That’s fine if you enjoy it, but I want to say clearly: a note directive and a 5-line query is enough to start.

Don’t let setup complexity prevent you from actually budgeting. The person who does rough ZBB with pen-and-paper categories and enters numbers into Beancount weekly is better off than the person who spends three months building the perfect automated system and never starts budgeting.

Start with Fred’s approach. The note directive is your budget. The expense accounts are your actual. The comparison is your feedback loop. That’s the whole system.

I want to bring the small business angle to this conversation because several of my clients have asked about ZBB, and the approach is slightly different when you’re budgeting for a business versus personal finances.

ZBB for Small Businesses in Beancount

For personal finance, Fred’s note-directive approach works great. But for businesses, I set up something more structured because clients need to compare budget vs. actual across months and present it to partners or lenders.

The Budget Directive Approach

Beancount actually has a built-in budget mechanism through custom directives that Fava understands:

; Monthly budget using Fava's native budget feature
2025-01-01 custom "budget" Expenses:Business:Rent       "monthly"  2500.00 USD
2025-01-01 custom "budget" Expenses:Business:Payroll     "monthly" 12000.00 USD
2025-01-01 custom "budget" Expenses:Business:Marketing   "monthly"  1500.00 USD
2025-01-01 custom "budget" Expenses:Business:Software    "monthly"   800.00 USD
2025-01-01 custom "budget" Expenses:Business:Supplies    "monthly"   300.00 USD
2025-01-01 custom "budget" Expenses:Business:Travel      "monthly"   600.00 USD
2025-01-01 custom "budget" Expenses:Business:Insurance   "monthly"   450.00 USD
2025-01-01 custom "budget" Expenses:Business:Misc        "monthly"   400.00 USD

Fava will show these in its budget view and you can see at a glance where you’re over and under. No manual comparison needed.

The Limitation

The built-in budget feature resets each period. If a client budgets $1,500/month for marketing but only spends $800 in January, the $700 doesn’t carry to February. For most businesses, that’s actually fine - you want fresh budget targets each month.

But for personal finance with sinking funds (saving for a vacation, new laptop, etc.), you want the rollover. That’s where fava-envelope comes in.

fava-envelope: The YNAB Experience in Beancount

To answer Fred’s question - yes, I’ve set up fava-envelope for two clients and for my own personal finances. It’s worth it if you want true envelope budgeting with rollover.

Here’s how it works:

; Install: pip install fava-envelope
; Add to your ledger:
2020-01-01 custom "fava-extension" "fava_envelope" "{}"

; Define envelope allocations
; This is like putting cash into envelopes at the start of the month
2025-02-01 custom "envelope" "allocate" "Expenses:Food" 600.00
2025-02-01 custom "envelope" "allocate" "Expenses:Fun" 400.00
2025-02-01 custom "envelope" "allocate" "Expenses:Transport" 200.00
2025-02-01 custom "envelope" "allocate" "Expenses:Clothing" 150.00

; You can map sub-accounts to parent envelopes
2025-01-01 custom "envelope" "mapping" "Expenses:Food:*" "Expenses:Food"

Fava then shows you an envelope view with columns for budgeted, spent, and remaining - and the remaining balance rolls forward to the next month. It’s basically YNAB inside Fava.

My Honest Assessment

Pros:

  • Real envelope rollover (sinking funds work properly)
  • Visual dashboard in Fava
  • Feels like YNAB but with Beancount’s power underneath

Cons:

  • Only supports a single currency
  • Setup takes an afternoon to get right
  • Documentation could be better
  • You have to manually add allocation lines each month (or script it)

The Hybrid Approach I Actually Recommend

For most people, especially beginners, I’d suggest this progression:

2025-01-01 note Equity "
=== ZBB PROGRESSION PATH ===

MONTH 1-3: Manual ZBB (Fred's approach)
  - Budget in note directives
  - Track expenses normally
  - Compare manually in Fava
  - GOAL: Build the habit

MONTH 4-6: Fava native budgets
  - Add 'custom budget' directives
  - Use Fava's built-in budget view
  - No rollover, fresh each month
  - GOAL: Automate the comparison

MONTH 7+: fava-envelope (if needed)
  - Add envelope plugin
  - Set up sinking funds
  - Get YNAB-style rollover
  - GOAL: Full envelope system

Not everyone needs to reach stage 3.
Many people are perfectly happy at stage 1 or 2.
The best budget system is the one you actually use.
"

Quick Tip for Variable Income

Fred asked about variable income. For my freelancer clients, I use what I call the “baseline budget”:

2025-01-01 note Income "
=== VARIABLE INCOME BUDGET STRATEGY ===

STEP 1: Identify your minimum reliable income
  Worst month in last 12: $4,200
  Second worst: $5,100
  BASELINE: $4,500 (conservative average of bad months)

STEP 2: Budget ONLY the baseline
  Fixed costs:    $2,800
  Flexible costs:   $700
  Minimum savings:  $500
  Buffer:           $500
  TOTAL:          $4,500

STEP 3: When actual income exceeds baseline
  Extra money follows priority list:
  1. Top up emergency fund to 3 months
  2. Extra debt payment
  3. Investment contribution
  4. Next month's buffer

NEVER increase your baseline budget because of
one good month. Only adjust quarterly based on
sustained income changes.
"

This way you never overspend based on expected income that might not materialize. Beancount is great for this because you can query your actual income history to set a realistic baseline.

Mike’s right that simplicity wins. But having the tools available when you’re ready for them is why I love the Beancount ecosystem.

Great discussion, and thanks for all the responses. Let me address the questions that came up.

Answering Sarah’s Questions

Budget vs Actual in Fava

Bob nailed it with the custom "budget" directives - I actually switched to those after writing my original post. Here’s what I use now:

; These give you a real budget view in Fava
; Go to the "Income Statement" and Fava shows budget bars
2025-01-01 custom "budget" Expenses:Food:Groceries    "monthly"  500.00 USD
2025-01-01 custom "budget" Expenses:Food:DiningOut     "monthly"  200.00 USD
2025-01-01 custom "budget" Expenses:Transport:Gas      "monthly"  200.00 USD
2025-01-01 custom "budget" Expenses:Personal:Fun       "monthly"  400.00 USD
2025-01-01 custom "budget" Expenses:Personal:Clothing  "monthly"  150.00 USD
2025-01-01 custom "budget" Expenses:Subscriptions      "monthly"  100.00 USD
2025-01-01 custom "budget" Expenses:Housing:Utilities   "monthly"  200.00 USD

I still keep the note directive as my “budget conversation with myself” each month, but the custom budget directives are what Fava actually uses to show you the progress bars. Best of both worlds.

Going Over Budget

When I go over in a category, I record the expense normally - don’t try to hide it or hack it. The whole point is to see reality. But I do add a note about what happened:

; Over-budget grocery run - documented why
2025-02-22 * "Costco" "Monthly stock-up + hosting dinner party"
  Expenses:Food:Groceries            145.00 USD
  Assets:Checking:Main              -145.00 USD
  ; NOTE: This puts groceries at $520, $20 over budget
  ; Reason: Hosting friends for dinner, planned
  ; Offset: Will reduce dining out by $20 this month

The “offset” note is key. In ZBB, when one category goes over, another has to go under. That’s the discipline. It’s not about never going over - it’s about consciously choosing where the extra comes from.

Separate Accounts vs Virtual Allocation

Sarah, you don’t need separate bank accounts for each savings goal. I have two accounts total: checking and a high-yield savings. The separate “accounts” in Beancount are just for tracking:

; My ACTUAL bank accounts: 2
; My Beancount accounts for savings: 4

; The physical money all lives in one HYSA
2025-01-01 open Assets:Savings:Emergency USD
2025-01-01 open Assets:Savings:Vacation USD
2025-01-01 open Assets:Savings:NewLaptop USD
2025-01-01 open Assets:Savings:CarRepair USD

; Monthly allocation (money moves to HYSA once)
2025-02-01 * "Transfer" "Monthly savings - all to HYSA"
  Assets:Savings:Emergency           500.00 USD
  Assets:Savings:Vacation            350.00 USD
  Assets:Savings:NewLaptop           150.00 USD
  Assets:Savings:CarRepair           100.00 USD
  Assets:Checking:Main             -1,100.00 USD

; In reality, this is ONE transfer of $1,100 to savings
; Beancount tracks the PURPOSE of each portion
; The bank doesn't know or care about the breakdown

This is one of Beancount’s superpowers - you can have logical accounts that don’t correspond 1:1 with real bank accounts. The balance directive confirms the physical total matches.

How Long to Get Categories Right

About 3 months of iteration. My first month I had 28 categories and wanted to die. My second month I collapsed it to 8 and felt better but missed some visibility. By month 3 I settled on 14 categories which is where I am now.

Mike’s advice about starting with 6 is solid. My only addition: keep a “Misc” or “Buffer” category that catches everything that doesn’t fit. At month-end, review what’s in Misc and decide if anything deserves its own category. That’s how your categories evolve organically.

The Rolling vs Reset Debate

Mike argues for resetting each month. I see his point, but I do a hybrid:

2025-03-01 note Assets:Checking:Main "
=== MARCH BUDGET - HYBRID ROLLOVER APPROACH ===

CATEGORIES THAT RESET (spending categories):
  Groceries: $500 (fresh each month)
  Dining out: $200 (fresh each month)
  Fun: $400 (fresh each month)
  Transport: $200 (fresh each month)

CATEGORIES THAT ROLL OVER (sinking funds):
  Vacation: $350/month, target $2,100 by July
  New laptop: $150/month, target $1,800 by December
  Car repair: $100/month, keeps accumulating
  Holiday gifts: $75/month, target $900 by November

Monthly spending resets.
Goal-based savings accumulate.
Surplus from spending categories goes to investments.
"

This gives me the fresh-start discipline for spending while letting sinking funds build toward their targets. I think pure reset or pure rollover both have drawbacks - the hybrid captures the best of both.

Six Months In: The Real Results

Since starting ZBB:

  • Savings rate went from 20% to 33%
  • Dining out dropped from $380/month to $190/month (I was shocked)
  • “Where did the money go?” moments: zero
  • Subscriptions I cancelled after seeing the budget: 4 ($67/month saved)
  • FIRE timeline improvement: 2.8 years earlier

The numbers don’t lie. For anyone on the fence - try it for one month. Just one. Set the budget on the 1st, track normally, and review on the 30th. If it doesn’t change how you think about spending, you’ve lost nothing. If it does, you’ve found something powerful.