After four years with Beancount, I can confidently say it was the right choice—but I didn’t start here. Like many in the plain text accounting world, my journey began with hledger. And honestly? hledger served me well for a solid 18 months before I felt the pull to migrate.
Let me share why I made the switch, and why investment lot tracking ended up being the deciding factor.
The hledger Years: What Worked
When I first discovered plain text accounting in 2022, I was tracking basic expenses and income across a few checking accounts and credit cards. hledger’s flexible, Ledger-compatible syntax felt natural. The command-line reports were fast, the ecosystem was welcoming, and I appreciated the “forgiving friend” philosophy—I could get started without worrying about declaring every account upfront.
For simple personal finance tracking, hledger absolutely delivered. I loved hledger bal, hledger reg, and the straightforward CSV import process. Everything just worked.
The Turning Point: Investments Enter the Picture
Then my financial life got more complex. I started seriously investing for financial independence, added two rental properties, and suddenly needed to track:
- Cost basis for individual stock and ETF lots (for capital gains reporting)
- Tax-loss harvesting opportunities across taxable brokerage accounts
- Wash sale tracking to avoid IRS violations
- Rental property expenses allocated correctly for depreciation
This is where I hit hledger’s limits. While hledger technically supports some lot syntax, it doesn’t have the robust infrastructure Beancount offers. Specifically:
Technical Comparison: Lot Syntax
hledger approach:
- Limited lot syntax support (can parse
{...}but doesn’t do much with it) - Manual workarounds using separate accounts for each lot
- No built-in capital gains calculation
- Cost basis tracking requires custom scripting
Beancount approach:
- Native
{}syntax for lot identification:100 AAPL {150.00 USD} - Built-in support for FIFO, LIFO, and specific lot identification
- Automatic unrealized gains calculation
- The fava_investor plugin for tax-loss harvesting identification
- Balance assertions work seamlessly with lots
Here’s a real example. In hledger, tracking a stock purchase looked like this:
2024-01-15 Buy AAPL
Assets:Brokerage:AAPL-Lot1 100 AAPL @ 150.00 USD
Assets:Brokerage:Cash -15000 USD
But then I’d have to manually create a new account for every lot and track cost basis in spreadsheets. Not sustainable.
In Beancount, it’s elegant:
2024-01-15 * "Buy AAPL"
Assets:Brokerage:Cash -15000.00 USD
Assets:Brokerage:AAPL 100 AAPL {150.00 USD}
When I later sell specific lots, Beancount automatically calculates my gain/loss:
2024-06-15 * "Sell AAPL - Tax Loss Harvest"
Assets:Brokerage:AAPL -50 AAPL {150.00 USD} @ 140.00 USD
Assets:Brokerage:Cash 7000.00 USD
Income:CapitalGains:LongTerm -500.00 USD
The system knows which lot I’m selling and tracks the $500 loss automatically.
The Migration Process
Once I decided to migrate, I used the hledger2beancount tool, which worked surprisingly well:
hledger print -f main.journal -O beancount > beancount.bean
The conversion handled about 85% of my transactions perfectly. I spent a weekend cleaning up:
- Adding explicit account opening declarations
- Fixing balance assertions (Beancount is stricter)
- Converting some hledger-specific tags to Beancount metadata
- Restructuring my lot tracking to use proper syntax
Time investment: ~10 hours total, spread over a week.
Biggest surprise: How much cleaner my ledger became. Beancount’s “strict teacher” approach forced me to fix inconsistencies I didn’t realize existed.
What Beancount Enables Now
Fast forward to today. Here’s what I can do now that would’ve been painful (or impossible) in hledger:
- Tax-loss harvesting dashboard: The
fava_investorplugin highlights loss opportunities in real-time - Accurate Form 8949 reporting: Cost basis for every sale, automatically calculated
- Wash sale tracking: Custom queries flag potential violations across accounts
- Portfolio rebalancing: Asset allocation reports that factor in unrealized gains
- Rental property P&L: Property-level income statements with proper expense categorization
The Fava web interface is the cherry on top. My spouse can now view our financial dashboard without touching the command line, which has been a relationship win.
Advice for Others Considering the Switch
You should stick with hledger if:
- You’re primarily tracking basic income/expenses without complex investments
- You love the command-line workflow and minimal setup
- You prefer hledger’s flexibility over Beancount’s strictness
- You’re happy with your current workflow
Consider Beancount if:
- You’re actively investing and need precise cost basis tracking
- Tax-loss harvesting or capital gains reporting matters to you
- You want a polished web UI (Fava) for visualizations
- You appreciate catching data errors early through strict validation
- You plan to automate imports and need Python ecosystem integration
No Regrets
I have nothing but respect for the hledger community and the tool itself. For the right use case, hledger absolutely shines. But for my needs—serious investment tracking, tax optimization, and audit-ready records—Beancount’s lot tracking capabilities were the clincher.
The migration wasn’t trivial, but it wasn’t scary either. And the payoff has been worth every hour invested.
If you’re on the fence, my advice: start simple with whichever tool resonates with you. But when your financial life gets complex—especially if investments are involved—take a serious look at Beancount’s lot tracking. It might just be the feature that tips the scale.
Have you migrated between plain text accounting systems? What was your deciding factor? Let’s hear your stories below.