Introduction to Beancount.io
This guide synthesizes best practices for plain-text accounting using the powerful, open-source, plain-text accounting tool, Beancount. It covers the foundational philosophy, basic-to-advanced syntax, practical case studies for complex assets, and long-term ledger management strategies.
Part 1: The "Why" - Foundations of Smart Bookkeeping
Before diving into the "how," it's crucial to understand the "why." Effective bookkeeping is the bedrock of personal financial management and a necessary step toward financial clarity and freedom.
Beyond Expense Tracking: The Path to Financial Clarity
Simple expense tracking apps tell you where your money went. A robust accounting system tells you that and much more: it provides a complete picture of your financial health, including your net worth, cash flow, and the performance of your investments. The primary goal is observability—gaining a clear, data-driven understanding of your financial life, which enables you to make informed decisions, assess risk, and work toward long-term goals like retirement.
Why Double-Entry? The Power of a Balanced System
Unlike single-entry bookkeeping (a simple list of expenses), the double-entry method records every transaction as a flow of value between at least two accounts. Its core principle is the fundamental accounting equation:
This system ensures that your books are always balanced, dramatically reducing errors. It provides a complete financial picture by generating essential reports like a Balance Sheet (what you own and owe) and an Income Statement (what you've earned and spent).
Part 2: Getting Started with Beancount
Beancount is a powerful, Python-based tool for plain-text accounting.
Your First Look with Fava on Beancount.io
Beancount.io provides a powerful environment that combines the Beancount engine with a mobile app (iOS, Android) and web app - Fava, a fantastic web-based interface for visualizing your ledger. There's no installation needed. When you use the platform, you are directly interacting with a text editor for your ledger file (e.g., main.bean
) and seeing the Fava-generated reports update in real-time.
Fava takes the plain text you write and turns it into interactive charts, financial statements, and filterable transaction lists, giving you a clear view of your financial reports.
The Five Core Account Types
Beancount uses five top-level account types, which form the structure of your ledger:
Account Type | Description | Typical Balance |
---|---|---|
Assets | What you own (cash, bank accounts, investments, property). | Positive |
Liabilities | What you owe (credit card debt, loans, mortgages). | Negative |
Income | Where money comes from (salary, bonuses, interest). | Negative |
Expenses | Where money goes (food, rent, travel, taxes). | Positive |
Equity | Your net worth; used for initial balances. | Negative |
The Beancount Equation
Beancount enforces its own version of the accounting equation where the sum of all postings across your entire ledger equals zero:
This is why, by convention, Income
, Liabilities
, and Equity
accounts hold negative values—they are the sources of funds that increase your Assets
and Expenses
.
Part 3: The Language of Beancount - Core Syntax
All entries in Beancount are directives that start with a date.
Defining Accounts (open
) and Commodities
Before you can use an account, you must declare it with the open
directive. You can also optionally specify the currencies or "commodities" it will hold.
; YYYY-MM-DD open Account:Name [Commodity1, Commodity2, ...]
2020-01-01 open Assets:Bank:US:Chase:Checking USD
2020-01-01 open Liabilities:CreditCard:US:Discover USD
2020-01-01 open Expenses:Food:Groceries
2020-01-01 open Income:Salary:Google
Commodities can be real-world currencies (e.g., USD
, JPY
) or any custom unit you define, like airline miles (MILES_UA
) or stock tickers (HOOL
).
Recording Your First Transaction (*
)
Transactions are the most common entry. They start with a date, a flag (*
for a complete transaction or !
for an incomplete one), an optional payee, and a description. Each line that follows (indented by two spaces) is a "posting" to an account.
; YYYY-MM-DD * "Payee" "Description"
; Account1 Amount Commodity
; Account2 -Amount Commodity
2024-07-28 * "Trader Joe's" "Weekly groceries"
Expenses:Food:Groceries 125.50 USD
Liabilities:CreditCard:US:Discover -125.50 USD
For convenience, if a transaction has only two postings, you can omit the amount on the second line, and Beancount will calculate it automatically.
2024-07-28 * "Trader Joe's" "Weekly groceries"
Expenses:Food:Groceries 125.50 USD
Liabilities:CreditCard:US:Discover
Transaction-Level Balancing: More importantly for day-to-day use, every individual transaction must also balance—the sum of all postings within a single transaction must equal zero. If a transaction doesn't balance, Beancount will show an error like this:
Handling Multi-Currency Transactions (@
and @@
)
Beancount excels at multi-currency accounting.
- Use
@
to specify a per-unit conversion price. - Use
@@
to specify the total cost of the conversion.
; Buying a flight in EUR with a USD card
2024-08-01 * "Lufthansa" "Flight to Berlin"
Expenses:Travel:Flights 500.00 EUR @@ 545.00 USD ; 500 EUR cost me 545 USD in total
Liabilities:CreditCard:US:Discover -545.00 USD
Part 4: Ensuring Accuracy - The Art of Reconciliation
A key practice for maintaining an accurate ledger is regular reconciliation. This involves comparing the balances in your Beancount ledger against official statements from your financial institutions.
Automating Checks with Balance Assertions (balance
)
The balance
directive is your primary tool for automated checks. You assert that on a given date, an account had a specific balance. Beancount will raise an error if its calculated balance doesn't match your assertion. This is invaluable for quickly locating errors.
Note: The balance assertion checks the state of the account at the beginning of the specified day (before any transactions on that day).
; From your monthly credit card statement
2024-08-01 balance Liabilities:CreditCard:US:Discover -1432.78 USD
Linking Supporting Documents (document
)
You can link to external files like bank statements or receipts, creating an auditable trail. Fava makes these links clickable.
2024-08-01 document Liabilities:CreditCard:US:Discover "statements/discover-2024-07.pdf"
Correcting Errors and Initializing Balances
When you start your ledger or find a discrepancy you can't trace, you need to make an adjustment. The standard practice is to use a special Equity
account.
; Initializing a cash account when starting your ledger
2020-01-01 * "Initial Balance" "Setting up cash account"
Assets:Cash:Wallet 200.00 USD
Equity:Opening-Balances -200.00 USD
The Equity:Opening-Balances
account holds amounts that enter your ledger from unknown or external sources.
For quick fixes where the exact discrepancy is unimportant, the pad
directive can automatically adjust an account's balance to meet a subsequent balance
assertion, booking the difference to an equity account. Use this with caution, as it can hide larger problems. Explicit adjustments are generally safer.
Part 5: Advanced & Realistic Transaction Patterns
Tracking Debts: Managing Receivables and Payables
Double-entry accounting is perfect for tracking money owed to you (Assets:Receivables
) or by you (Liabilities:Payable
).
Example: You pay for a group dinner of 45 share.
-
Record the initial expense and the receivable:
2024-08-05 * "Dinner Place" "Dinner with Bob"
Expenses:Food:Restaurant 45.00 USD ; Your share
Assets:Receivables:Bob 45.00 USD ; Bob owes you
Assets:Bank:US:Chase:Checking -90.00 USD -
When Bob pays you back:
2024-08-06 * "Bob" "Paid me back for dinner"
Assets:Bank:US:Chase:Checking 45.00 USD
Assets:Receivables:Bob -45.00 USD
The Assets:Receivables:Bob
account is now zero, and your books are perfectly balanced.
Assets vs. Expenses: A Car Purchase and Depreciation
A large purchase like a car is not a simple expense; it's the acquisition of an asset that loses value over time (depreciation).
-
Record the purchase as an asset:
2023-01-15 * "Toyota Dealer" "Purchase of a new car"
Assets:Car:ToyotaCamry 30000.00 USD
Assets:Bank:US:Chase:Checking -30000.00 USD -
Record annual depreciation: Assume you estimate the car loses $3,000 in value each year. At the end of the year, you record this as an expense.
2023-12-31 * "Depreciation" "Annual car value depreciation"
Expenses:Depreciation:Car 3000.00 USD
Assets:Car:ToyotaCamry -3000.00 USD
After this entry, your Assets:Car:ToyotaCamry
account correctly reflects the car's new value ($27,000), and you've properly accounted for the usage cost as an expense for that year.
Part 6: Deep Dive - Modeling Complex Real-World Assets
Case Study 1: Accounting for Real Estate
A home is often your largest asset and liability. Here’s how to model it.
-
Create Accounts and a Custom Commodity:
2022-01-01 commodity HOUSE_123MAIN
name: "Property at 123 Main St"
2022-01-01 open Assets:Property:Home:123Main HOUSE_123MAIN
2022-01-01 open Liabilities:Mortgage:HomeLoan USD
2022-01-01 open Expenses:Home:Interest
2022-01-01 open Expenses:Home:PropertyTax -
Record the Purchase: Let's say you buy a 100k down payment and a $400k loan.
2022-03-15 * "Settlement Company" "Purchase of 123 Main St"
Assets:Property:Home:123Main 1 HOUSE_123MAIN {500000.00 USD}
Assets:Bank:DownPayment -100000.00 USD
Liabilities:Mortgage:HomeLoan -400000.00 USD -
Record Monthly Mortgage Payments: Your monthly payment consists of principal (reduces liability) and interest (an expense).
2022-04-01 * "Mortgage Bank" "Monthly Mortgage Payment"
Liabilities:Mortgage:HomeLoan 800.00 USD ; Principal
Expenses:Home:Interest 1200.00 USD ; Interest
Assets:Bank:US:Chase:Checking -2000.00 USD -
Tracking Appreciation (Unrealized Gains): A house's market value changes. To track this without affecting your official net worth (as the gain is not realized until you sell), you can use a price directive with a "virtual" currency.
; The purchase price is the real cost basis
2022-03-15 price HOUSE_123MAIN 500000.00 USD
; An updated market estimate is an unrealized gain
2024-01-01 price HOUSE_123MAIN 550000.00 USD.UNREALIZED
This allows you to see the estimated value in Fava's charts without improperly inflating your balance sheet.