Reads and writes means the app both understands it and can produce it. Reads and keeps means the app understands it, values it, and leaves it exactly as you wrote it, but will not create one for you. Neither ever changes what is already in your files beyond the entry you are editing.
This is a reference for what the app supports, not a beancount tutorial. For the format itself, the official documentation is the place to start, and the compatibility table lists every construct in addition to the ones with an example here.
These examples in one file: example-ledger.bean. Save it into an empty folder and open that folder, in Beanie Budgets or in anything else that reads beancount.
Found something we missed? We have worked hard to cover beancount's syntax, checking the app against real beancount across thousands of generated ledgers and against grammars and specifications written by other people. However, Beancount is a big language and this is a new app so we probably still have gaps. If you find that a line of your ledger loads in bean-check but not in Beanie Budgets we would like to know about it. The app lists any lines it can't read under Settings, each with a code, please send these errors to us.
Opening Accounts
Every account has to be opened before anything can be posted to it. The app writes these for you when you add an account, and reads whatever is already in your file.
Opening an account
A date, the word open, and the account. Naming a currency after it keeps the account to that one, and beancount will refuse a posting in anything else.
2026-01-01 open Assets:Bank:Current GBP 2026-01-01 open Expenses:Food:Groceries GBP
An account that can hold anything
Leave the currency off and the account will take whatever you post to it. Useful for an expense account you might one day spend abroad from.
2026-01-01 open Expenses:Travel
An account in more than one currency
List them separated by commas. A travel account holding both pounds and euros is the typical reason to want this.
2026-01-01 open Assets:Bank:Travel GBP,EUR 2026-05-04 * "Bureau de change" "Euros for the trip" Assets:Bank:Travel 400.00 EUR Equity:Opening-Balances
Beancount holds you to the list of currencies: a posting in a currency you did not name is refused.
How shares should be sold
An investment account can say which lot a sale takes: FIFO, LIFO, HIFO, AVERAGE, STRICT or NONE. The text in quotes stands for, in order, oldest first, newest first, dearest first, a blended average, naming the lot yourself, and no matching at all.
2026-01-01 open Assets:Brokerage:VWRL VWRL "FIFO" 2026-01-01 open Assets:Brokerage:VUSA VUSA "LIFO"
Warning! If you don't use quotes, beancount reads it as the name of a commodity the account may hold, not as a booking method: open Assets:Brokerage FIFO passes bean-check and declares an account holding a commodity called FIFO. Beanie Budgets reads it the same way beancount does.
Details against an account
Indented key: value lines under an open hold whatever you want to remember about the account.
2026-01-01 open Assets:Bank:Savings GBP institution: "Nationwide" sort-code: "07-01-16"
Kept exactly as you wrote them, including through an account rename. The app does not add them itself.
Closing an account
When an account is finished with, close records the date. Beancount then refuses anything posted to it afterwards, which is a useful check against a stray entry.
2020-01-01 open Assets:Bank:Old-Savings GBP 2026-02-28 close Assets:Bank:Old-Savings
Read and kept, and rewritten correctly if you rename the account. Beanie Budgets does not yet hide the account in the app.
What an account name may contain
The first part has to be one of beancount's five roots: Assets, Liabilities, Equity, Income or Expenses. Every part after it may start with a capital or a digit, and may contain hyphens, so a pension scheme or a tax year works as a name.
2026-01-01 open Assets:Retirement:401K:Cash 2026-01-01 open Expenses:Taxes:2026:Payments-On-Account 2026-01-01 open Liabilities:Non-current:Mortgage
Basic Transactions
The shape almost every line in a ledger takes: a date, who it was with, and where the money went. Everything here is read and written by the app unless a note says otherwise.
A transaction
A date, a flag, who you paid, what it was for, and the two sides of the money. The * means settled; every posting is an account and an amount.
2026-03-14 * "Sainsbury's" "Weekly shop" Expenses:Food:Groceries 42.18 GBP Assets:Bank:Current -42.18 GBP
Letting beancount work out the other side
Leave the last amount off and it is whatever balances the transaction. Handy, and worth keeping for the side you care least about: an inferred posting can never be wrong, because it is defined as whatever makes the books balance.
2026-03-02 * "Octopus Energy" "February electricity" Expenses:Home:Electricity 88.40 GBP Assets:Bank:Current
Splitting one payment
A transaction can have as many postings as you like, so one card payment can be broken into what it was actually spent on.
2026-03-19 * "Tesco" "Shop and a new kettle" Expenses:Food:Groceries 31.05 GBP Expenses:Home:Supplies 24.00 GBP Liabilities:Card:Visa -55.05 GBP
Marking a transaction as not settled yet
A ! in place of the * marks a transaction you are not sure about, so you can come back to it. Beancount reads it the same way; the flag is just a note to yourself.
2026-03-21 ! "Uber" "Airport, receipt to check" Expenses:Travel:Taxi 64.00 GBP Assets:Bank:Current -64.00 GBP
Tags and links
A #tag groups transactions by theme, and a ^link ties together the several entries that make up one event, such as a trip paid for in instalments.
2026-04-02 * "easyJet" "Flights out" #holiday-2026 ^lisbon-trip Expenses:Travel:Flights 218.60 GBP Assets:Bank:Current -218.60 GBP
Notes against a transaction or a posting
Any key: value line adds your own detail. Indented under the header it belongs to the whole transaction; indented under a posting it belongs to that posting alone.
2026-03-28 * "Ace Plumbing" "Boiler service"
invoice: "INV-2291"
Expenses:Home:Repairs 145.00 GBP
warranty-until: 2027-03-28
Assets:Bank:Current -145.00 GBP
Comments
Anything after a semicolon is ignored, on its own line or at the end of one. Useful for explaining a transaction to yourself, and kept exactly where you put it.
; Christmas presents, split with my sister 2026-12-03 * "John Lewis" "Present for Mum" Expenses:Gifts 60.00 GBP ; her half comes back in January Assets:Bank:Current -60.00 GBP
Sums and separators in an amount
An amount can be written as a calculation, and long numbers can carry thousands separators. Both are read and kept exactly as you wrote them.
2026-03-01 * "Landlord" "March rent" Expenses:Home:Rent 1,250.00 GBP Assets:Bank:Current -1,250.00 GBP 2026-03-08 * "Dishoom" "Dinner, split four ways" Expenses:Food:Restaurant 112.00 / 4 GBP Assets:Bank:Current
The app keeps these as written for as long as the amount is unchanged. Entries it writes itself use plain numbers.
Advanced Transactions
Buying and selling something whose price moves. These are the lines the app reads and values but will not write for you.
Buying shares at a cost
Braces hold what each unit cost. The account then holds ten units of VWRL rather than a sum of money, and the app values them at whatever your latest price says.
2026-01-15 * "Vanguard" "Buy VWRL"
Assets:Brokerage:VWRL 10 VWRL {90.00 GBP}
Assets:Brokerage:Cash -900.00 GBP
One cost for the whole lot
Double braces mean the figure covers the posting rather than each unit, which is how a dividend reinvestment or a fractional purchase usually arrives from a broker. Beancount divides it across the units for you.
2026-02-10 * "Vanguard" "Reinvested dividend"
Assets:Brokerage:VUSA 5.482 VUSA {{465.00 GBP}}
Assets:Brokerage:Cash -465.00 GBP
A price rather than a cost
An @ records what a unit changed hands for without giving the holding a cost basis. Beancount keeps the position as bare units, and so does the app: there is no gain to report because nothing says what was paid.
2026-01-20 * "Vanguard" "Buy VMID" Assets:Brokerage:VMID 40 VMID @ 30.50 GBP Assets:Brokerage:Cash -1,220.00 GBP
Worth knowing because it surprises people: 40 VMID @ 30.50 GBP gives the account forty units and no cost basis. bean-query and Fava say the same, and the app matches them rather than inventing a basis from the price.
Selling, naming the lot
A sale repeats the cost it was bought at, gives the price it went for, and leaves the gain to be worked out. The bare Income posting picks up the difference.
2026-01-05 * "Vanguard" "Buy VFEM"
Assets:Brokerage:VFEM 20 VFEM {48.00 GBP}
Assets:Brokerage:Cash -960.00 GBP
2026-06-12 * "Vanguard" "Sell half"
Assets:Brokerage:VFEM -10 VFEM {48.00 GBP} @ 55.00 GBP
Assets:Brokerage:Cash 550.00 GBP
Income:Investments:Gains
Choosing which lot by date
Where two lots cost the same, the date in the braces says which one is being sold. Useful when your broker's statement identifies a holding by when you bought it rather than by what you paid.
2026-01-08 * "Vanguard" "First VAGP purchase"
Assets:Brokerage:VAGP 10 VAGP {25.00 GBP}
Assets:Brokerage:Cash -250.00 GBP
2026-04-08 * "Vanguard" "Second, at the same price"
Assets:Brokerage:VAGP 10 VAGP {25.00 GBP}
Assets:Brokerage:Cash -250.00 GBP
2026-07-02 * "Vanguard" "Sell the April lot"
Assets:Brokerage:VAGP -10 VAGP {2026-04-08} @ 27.00 GBP
Assets:Brokerage:Cash 270.00 GBP
Income:Investments:Gains
Letting the account decide which lot
Empty braces say only that a lot is being reduced, and leaves the choice to the booking method on the account. This one is FIFO, so the oldest goes first.
2026-01-01 open Assets:Brokerage:VHYL VHYL "FIFO"
2026-02-02 * "Vanguard" "First VHYL purchase"
Assets:Brokerage:VHYL 10 VHYL {50.00 GBP}
Assets:Brokerage:Cash -500.00 GBP
2026-05-02 * "Vanguard" "Second, dearer"
Assets:Brokerage:VHYL 10 VHYL {60.00 GBP}
Assets:Brokerage:Cash -600.00 GBP
2026-08-02 * "Vanguard" "Sell ten, oldest first"
Assets:Brokerage:VHYL -10 VHYL {} @ 65.00 GBP
Assets:Brokerage:Cash 650.00 GBP
Income:Investments:Gains
The app reads the booking method and works the disposal out the same way beancount does. It will not add a booking method to an account for you.
Commission folded into the cost
A # inside the braces adds a dealing charge to the lot rather than expensing it separately. Beancount spreads it across the units, so these three cost 95.00 each plus 4.95 between them.
2026-03-03 * "Vanguard" "Buy VUKE with dealing charge"
Assets:Brokerage:VUKE 3 VUKE {95.00 # 4.95 GBP}
Assets:Brokerage:Cash -289.95 GBP
What a holding is worth today
A price line records a quote on a date. This is what lets the app value a holding at anything other than what you paid for it, and what puts it into your net worth in your own currency.
2026-06-01 price VWRL 101.50 GBP 2026-07-01 price VWRL 104.25 GBP
Only a price line is used for valuing. The @ on the transaction that bought the holding is not.
Buying foreign currency
The rate goes on the posting as an @, which is what lets the two sides balance across currencies. The dollars then sit in the account as dollars.
2026-05-06 * "Wise" "Dollars for the trip" Assets:Bank:Dollars 1,000.00 USD @ 0.79 GBP Assets:Bank:Current -790.00 GBP
To show those dollars in pounds the app needs a price USD 0.79 GBP line as well. Without one it shows what you hold in dollars rather than converting at a rate your file never states, which is what beancount does with the same file.
Assertions
Lines that check your ledger against reality rather than recording anything. This is what stops a mistake from six months ago quietly sitting in your balance, and the app writes these for you when you use Correct Balance.
Checking a balance
A balance line says what an account should hold on a date. If it does not, beancount tells you, and so does the app.
2026-03-01 * "Opening" Assets:Bank:Joint 1,234.56 GBP Equity:Opening-Balances 2026-04-01 balance Assets:Bank:Joint 1,234.56 GBP
Checked at the start of its date, before anything else that day. So a statement balance on the 31st is asserted on the 1st of the following month.
Allowing for a penny or two
Adding ~ and an amount accepts anything within that much, which is useful where a provider rounds differently from your ledger.
2026-03-01 * "Opening" Assets:Pension:Workplace 1,234.58 GBP Equity:Opening-Balances 2026-04-01 balance Assets:Pension:Workplace 1,234.56 ~ 0.05 GBP
Making an account match a known figure
A pad before a balance inserts whatever entry is needed to make the assertion come out right. This is how an opening balance is normally written, and what the app's Correct Balance does.
2026-01-01 pad Assets:Bank:Savings Equity:Opening-Balances 2026-01-02 balance Assets:Bank:Savings 8,500.00 GBP
The padding entry is generated rather than written into your file, so changing the figure in the balance line changes what the pad contributes. The pad has to be dated strictly before the assertion.
Checking a holding rather than a sum
An assertion works in whatever the account holds, so a share count can be checked against a broker statement without knowing what it was worth that day.
2026-01-15 * "Transfer in"
Assets:Brokerage:VMIG 10 VMIG {90.00 GBP}
Equity:Opening-Balances
2026-04-01 balance Assets:Brokerage:VMIG 10 VMIG
Organising a Ledger
Once a ledger has a few years in it, it stops being one file. These are the lines that hold it together and describe it.
Splitting into several files
An include pulls another file in, so accounts, prices and each year's transactions can live apart. Paths are relative to the file doing the including.
; main.bean include "accounts.bean" 2026-03-04 * "Co-op" "Shop" Expenses:Food:Groceries 18.40 GBP Assets:Bank:Current
Including a whole folder
A wildcard saves listing every file by name, which is what you want once each year or each account type has its own.
include "accounts/*.bean" 2026-03-04 * "Co-op" "Shop" Expenses:Food:Groceries 18.40 GBP Assets:Bank:Current
Telling beancount about the file
operating_currency is the one that matters most: it is the currency your totals are shown in, and the app reads it to know what your net worth should be counted in.
option "title" "Our household ledger" option "operating_currency" "GBP"
Tagging a run of transactions
Everything between a pushtag and its poptag picks up the tag, which beats writing it on twenty entries from one holiday.
pushtag #lisbon-2026 2026-05-05 * "Hotel Lisboa" "Two nights" Expenses:Travel:Hotel 180.00 GBP Assets:Bank:Current 2026-05-06 * "Time Out Market" "Dinner" Expenses:Food:Restaurant 42.00 GBP Assets:Bank:Current poptag #lisbon-2026
The pushed tag reaches every transaction inside and stops at the pop. The app shows those transactions tagged, and keeps the pushtag/poptag pair where you put it.
Describing a commodity
A commodity line gives a ticker a readable name, and any metadata you want alongside it.
2026-01-01 commodity VWRL name: "Vanguard FTSE All-World UCITS ETF" asset-class: "Equity"
The app reads asset-class and uses it for the Allocation report, so declaring it is worth the two lines.
A note against an account
A dated note about an account.
2026-02-14 note Assets:Bank:Current "Rang them about the overdraft fee"
A document line works the same way for a file path, and is read and kept, though beancount refuses the file if the document is not actually there, so there is no example of one here.
A budget
Fava's budget directive sets what you mean to spend on a category over a period. The app reads these and drives Budget Monitoring from them.
2026-01-01 custom "budget" Expenses:Food:Groceries "monthly" 400.00 GBP 2026-01-01 custom "budget" Expenses:Travel "yearly" 2,000.00 GBP
A transaction that repeats
A bracketed instruction at the end of the narration turns one entry into a series, so a rent payment or a subscription is written once. UNTIL a date, or REPEAT n TIMES.
2026-01-01 * "Landlord" "Rent [MONTHLY UNTIL 2027-01-01]" Expenses:Home:Rent 1,250.00 GBP Assets:Bank:Current 2026-01-05 # "Netflix" "Subscription [MONTHLY REPEAT 12 TIMES]" Expenses:Subscriptions 10.99 GBP Assets:Bank:Current
The occurrences are worked out as the file is read rather than written into it, so your file keeps the one entry. Either flag works, and # is the one Fava's own forecast plugin uses.