Skip to main content

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:

Assets=Liabilities+Equity (Net Worth)\text{Assets} = \text{Liabilities} + \text{Equity (Net Worth)}

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 TypeDescriptionTypical Balance
AssetsWhat you own (cash, bank accounts, investments, property).Positive
LiabilitiesWhat you owe (credit card debt, loans, mortgages).Negative
IncomeWhere money comes from (salary, bonuses, interest).Negative
ExpensesWhere money goes (food, rent, travel, taxes).Positive
EquityYour 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:

Assets+Expenses+Liabilities+Income+Equity=0\text{Assets} + \text{Expenses} + \text{Liabilities} + \text{Income} + \text{Equity} = 0

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:

Beancount Error Alert

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 90,andyourfriendBobowesyouforhis90, and your friend Bob owes you for his 45 share.

  1. 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
  2. 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).

  1. 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
  2. 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.

  1. 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
  2. Record the Purchase: Let's say you buy a 500khousewitha500k house with 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
  3. 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
  4. 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.

Case Study 2: Tracking Restricted Stock Units (RSUs)

RSUs are a common form of equity compensation. Accounting for them involves tracking the initial grant, vesting events, and tax withholding.

  1. Initial Setup: Create commodities for vested (HOOL) and unvested (HOOL.UNVEST) stock, along with necessary accounts.

    2021-01-01 commodity HOOL
    2021-01-01 commodity HOOL.UNVEST
    2021-01-01 open Assets:Brokerage:Etrade:HOOL HOOL
    2021-01-01 open Assets:Grant:Unvested HOOL.UNVEST
    2021-01-01 open Income:Salary:Hooli:RSU
    2021-01-01 open Expenses:Taxes:Federal
  2. Record the Initial Grant: This transaction shows the total grant moving into an unvested asset account.

    2021-02-01 * "Hooli" "Initial RSU Grant"
    Assets:Grant:Unvested 1000 HOOL.UNVEST
    Income:Grant:Awards -1000 HOOL.UNVEST
  3. Record a Vesting Event: This is the key transaction. When shares vest, you recognize income, pay taxes (often by selling some shares), and receive the net shares. Assume 100 shares vest at $150/share.

    2022-02-01 * "Hooli" "RSU Vesting Event"
    ; Recognize total income of 100 * $150 = $15,000
    Income:Salary:Hooli:RSU -15000.00 USD

    ; Show taxes paid from this income
    Expenses:Taxes:Federal 4000.00 USD
    Expenses:Taxes:State 1000.00 USD

    ; You receive the net shares (assume 60 shares) at their cost basis
    Assets:Brokerage:Etrade:HOOL 60 HOOL {150.00 USD}

    ; The other 40 shares were sold to cover $6000 in taxes.
    ; This transaction balances the income, taxes, and received shares.
    ; We must also show the reduction in unvested shares.
    Assets:Grant:Unvested -100 HOOL.UNVEST
    Expenses:Grant:Vested 100 HOOL.UNVEST

This single, balanced transaction correctly models the entire event: the unvested grant is reduced, income is recognized, taxes are paid, and the net vested shares appear in your brokerage account with the correct cost basis for future capital gains calculations.

Part 7: Project Management for Your Ledger

As your ledger grows, organization becomes key.

Using Version Control (Git) to Safeguard Your Data

Since your ledger is a text file, it's perfect for version control with Git. This gives you a complete history of all changes, protecting you from accidental deletions or mistakes. Warning: Your financial data is highly sensitive. Use a private repository on services like GitHub/GitLab, or host your own.

Beancount provides two ways to group transactions beyond accounts:

  • Tags (#): Use for events or projects. You can filter all transactions related to a specific trip, for example. 2024-07-20 * "Hotel" "Vienna" #trip-europe-2024
  • Links (^): Use to connect financially related transactions that occur at different times, such as a cash withdrawal and the associated bank fee.

A Scalable Strategy for Structuring Your Files (include)

A single, massive file is hard to manage. Use the include directive to split your ledger into multiple files. main.bean:

; Main ledger file

; Global options
option "title" "My Personal Ledger"
option "operating_currency" "USD"

; Include account declarations and other files
include "accounts.bean"
include "years/2023.bean"
include "years/2024.bean"
include "events/trip-europe-2024.bean"

A robust organizational strategy, in order of precedence:

  1. By Event: Create a separate file for a major, self-contained event (e.g., trip-europe-2024.bean).
  2. By Category/Payee: For highly regular, recurring transactions like utility bills or salary, group them in their own file (e.g., recurring-rent.bean).
  3. By Account: For transactions tightly coupled to a specific account (interest, fees, credit card payments), consider an account-specific file.
  4. By Date: For all other general transactions, a simple split by year (2024.bean) or month (2024/07.bean) is effective.

Part 8: Conclusion

Beancount offers a steep learning curve but rewards the effort with unparalleled power, flexibility, and control over your financial data. By embracing the principles of double-entry accounting and the practical tools Beancount provides, you can move from simple expense tracking to a complete, accurate, and insightful system of personal financial management. Your ledger becomes a permanent, private, and invaluable asset for understanding your past and planning your future.

Getting Started with Beancount.io

Beancount.io is a modern cloud-based financial management platform that transforms your text-based transaction records into comprehensive financial statements, including income statements, balance sheets, and trial balances. By combining the reliability of plain text files with powerful visualization tools, Beancount.io helps you maintain precise control over your financial life while gaining valuable insights into your investment performance.

Start your financial journey with Beancount.io - Free during our promotional period!

Expenses

Income Statement

Balance Sheet