Skip to content

Budget

Zhang’s budgets follow the envelope model of YNAB (You Need A Budget): you create a budget for a spending category, assign money to it each month, and link expense accounts to it. Spending on those accounts is the budget’s activity, and what is left carries over to the next month. Budgets are separate from your accounts: they never change an account’s balance.

YYYY-MM-DD budget <Name> <Commodity>
YYYY-MM-DD budget-add <Name> <Number> <Commodity>
YYYY-MM-DD budget-transfer <FromName> <ToName> <Number> <Commodity>
YYYY-MM-DD budget-close <Name>
Directive Effect
budget Creates the budget <Name>, counted in <Commodity>.
budget-add Assigns an amount to the budget in the month of its date. A negative amount takes money away.
budget-transfer Moves an assigned amount from one budget to another in the month of its date.
budget-close Closes the budget from the month of its date.

A budget name is a single word without spaces, quotes, colons, parentheses or commas, such as Food or Daily-Groceries. Each directive takes a date, optionally with a time of day, and metadata lines below.

A budget directive reads two metadata keys:

Key Effect
alias A display name for the budget in the web UI.
category The group the budget page lists the budget under.

An account counts toward a budget through the budget metadata of its open directive. Repeat the key to link the account to several budgets. A posting counts toward the budgets of the account’s open in effect at its date, so an account closed and opened again with other budget metadata counts toward the new budgets from its reopening on.

YYYY-MM-DD open <Account>
budget: <Name>
2024-01-01 budget Food CNY
alias: "Food and groceries"
category: "Daily"
2024-01-01 budget Fun CNY
category: "Discretionary"
2024-01-01 open Assets:Bank:Checking CNY
2024-01-01 open Expenses:Groceries CNY
budget: Food
2024-01-01 open Expenses:Restaurants CNY
budget: Food
2024-01-01 open Expenses:Movies CNY
budget: Fun
2024-01-01 budget-add Food 2000 CNY
2024-01-01 budget-add Fun 300 CNY
2024-01-12 * "Supermarket" "weekly shopping"
Assets:Bank:Checking -420.00 CNY
Expenses:Groceries
2024-01-20 budget-transfer Fun Food 100 CNY

In January, Food has 2100 CNY assigned, 420 CNY of activity and 1680 CNY available; Fun has 200 CNY available.

Budgets work month by month. For each budget and month, Zhang keeps:

  • assigned: what budget-add and budget-transfer put into the budget, plus what was available at the end of the previous month;
  • activity: the postings to the linked accounts in that month. Spending on an expense account increases it, a refund decreases it;
  • available: assigned minus activity. At the start of the next month, it becomes that month’s assigned amount, so money left over, or overspent, carries over.

Some details:

  • A budget exists from the date of its budget directive. A posting to a linked account before that date is not counted, and is reported once as BudgetDoesNotExist.
  • The amounts of budget-add and budget-transfer, and the postings, are converted to the budget’s commodity at their date, with the prices of the ledger. An amount that no price converts is left out.
  • budget-close closes the budget from the month of its date: the budget page shows it as closed in that month and the months after, and the budget card of the home page leaves it out from then on. A later budget-close changes nothing. Later directives and postings still count toward it.
  • The budget page of the web UI shows the assigned, activity and available amounts of each budget for a month, and the events of a budget in a month. In queries, #budgets and #budget_events hold the same figures; see Zhang-specific tables.
Error When
DefineDuplicatedBudget A budget directive names a budget that already exists. The second directive is ignored.
BudgetDoesNotExist A budget-add, budget-transfer or budget-close names a budget that is not defined at its date; the directive is ignored. Or a posting’s account is linked to a budget that is not defined at the posting’s date; this is reported once per account and budget, and the transaction is still booked.

Beancount has no budget directives. In a Beancount file, write them as custom directives in the form Beancount itself accepts: a quoted type, quoted budget names, a quoted commodity for budget, and a plain amount for budget-add and budget-transfer:

Zhang Beancount file
2024-01-01 budget Food CNY 2024-01-01 custom "budget" "Food" "CNY"
2024-01-01 budget-add Food 2000 CNY 2024-01-01 custom "budget-add" "Food" 2000 CNY
2024-01-20 budget-transfer Fun Food 100 CNY 2024-01-20 custom "budget-transfer" "Fun" "Food" 100 CNY
2024-12-31 budget-close Food 2024-12-31 custom "budget-close" "Food"

Metadata lines follow as usual. bean-check and Fava accept these lines as ordinary custom entries; Zhang reads them as budgets and writes budgets this way into Beancount files. The unquoted form earlier versions of Zhang wrote, custom budget Food CNY, is still read, so existing ledgers keep working, but Beancount rejects it (Invalid token): switch to the quoted form when you also check the ledger with bean-check. A custom "budget" with other values, such as Fava’s own budget entries (custom "budget" Expenses:Coffee "daily" 4.00 EUR), stays an ordinary custom directive.

  • Budgets: setting up and using budgets.
  • Account: the budget metadata of an account.