Beancount Schema Evolution: Refactoring After 5 Years Without Breaking Audit Trail

So I’ve been using Beancount for about 5 years now—came from GnuCash and haven’t looked back. But I’m hitting a real credibility problem with my chart of accounts.

When I started, I created: Expenses:Transportation:Auto:Fuel:Premium and Expenses:Transportation:Auto:Fuel:Regular, which felt good. Then insurance, maintenance, tolls got nested the same way. Fast forward to now—I’ve got this sprawling hierarchy that made sense at the time but creates friction every time I reconcile or generate reports. I’m running queries like SELECT * FROM postings WHERE account ~ "Expenses:Transportation.*Fuel.*" just to see my actual gas spending.

And here’s my anxiety: I’ve got 5 years of entries referencing these accounts. If I rename/reorganize, will Git history stay intact? Can auditors still trace where things came from? Or do I need to rewrite history (which feels dangerous)?

Have any of you refactored a mature Beancount ledger? How did you handle it without losing the audit trail that makes plain text accounting so trustworthy?

I did this for a client last year. They were 3 years in Beancount with ~2,400 transactions and a frankly disorganized chart.

Key insight: Git history is immutable. When I renamed accounts—say Expenses:Misc:Office to Expenses:Admin:Supplies—the old transactions in the log stayed exactly as written. The current ledger shows new names, but git blame still shows the original. For audit purposes, you get both views: “what it looks like now” and “what was originally recorded.”

The CPA actually appreciated this duality. They could see the intent to reorganize and the original record. Real issue: if you rename retroactively, old entries reference nonexistent accounts in the current file. So either alias them or accept two eras of your ledger.

What I learned: don’t overthink it. Refactoring is possible and auditable.

Quick clarification: when you queried the renamed accounts, did the Git history actually become unsearchable, or just inconsistent to read?

This is really helpful, Bob. Reframing refactoring as “augmenting” rather than “breaking” changes how I think about this.

For Fred’s question: I think the key is that Beancount won’t retroactively rewrite the file. Old entries keep their original account names; renaming in place just means your current working file has some obsolete-looking accounts mixed with recent ones.

The alias solution is genuinely elegant—queries work across both eras without a cutover. I’m going to run both names in parallel for a month, then retire the old one.

My core anxiety was: “will my auditor think I’m hiding something?” Your CPA sign-off is the reassurance I needed. Git’s immutability actually makes the trail stronger when you refactor thoughtfully.

The alias solution is genuinely elegant—queries work across both eras without a cutover.

I get it, but I’ll push back on that. My client started with aliases and ended up with two sets of accounts in their reports. It created its own confusion. Eventually we bit the bullet, renamed everything, documented the migration in Git, and called it done. Cleaner in the long run.