I have used a number of budgeting tools in the past to take control over my finances, but none have ever checked all my boxes. The latest and perhaps most interesting tool I have discovered is ledger-cli.

Ledger is “a powerful, double-entry accounting system that is accessed from the UNIX command-line.” In my own terms, it is plain text budgeting tool that allows for a high-level of customization while also remaining easily readable to human eyes. There are a number of guides to getting started using ledger and the ledger manual itself contains extensive documentation. Despite all of the available documentation, guides and my eagerness to find the perfect budgeting tool, I found that ledger is one of those tool learned best by getting your hands dirty. Instead of detailing the ins and outs of ledger, I wanted to give a basic example you can execute, break and fix.

Before getting started you may also want to look into double-entry accounting. Simply, double-entry accounting requires that every transaction must balance to zero through an opposing transaction in one or more accounts. If you take $10 out of your savings account you need to show that same $10 flowing into another account such as your cash wallet or a friend that you paid back. Understanding the basic concept is enough to get started. Additionally, other guides will likely do a better job of explaining double-entry accounting than I would be able to, so I will leave that out of scope for this post.

Create your Journal File

Ledger refers to its files as journal files. These files are the source of truth for your financial data. You will most commonly interact with them to record all of your financial transactions, but they also be used to define your accounts. The basic syntax is shown in the example below. For more advanced syntax and you should refer back to the ledger manual.

To start create a file with the contents of the snippet below. You can save it under any name, but the below commands will assume you have saved the file as main.journal.

; This is a journal file
; A semi-colon is one way to create a comment

; 1.
; Below is a simple transaction.
; This transaction occurred on 2019/11/01
; The transaction details let us know that it is a withdrawal of cash from a saving account.
2019/11/01  WITHDRAWLING CASH
    assets:wallet     100.00
    assets:savings     -100.00

; 2.
; Here is another simple transaction.
; This transaction shows us paying 5.00 dollars for coffee from our wallet
2019/11/02 BUYING A BOOK
    expenses:reading   5.00
    assets:wallet     -5.00


; 3.
; This is a transaction showing what a paycheck might look like in ledger
; Note that we do not have to __explicitly__ balance this transaction to our income account
; Ledger will handle the balancing implicitly for this account when the balance ammount is ommitted.
2019/11/03 PAYCHECK
    assets:savings      130.00
    income

; 4.
; This is showing multiple transactions on the same date being implictly balanced
; Note that accounts can be as specific as you need them to be.
2019/11/04 LUNCH AND ICECREAM
    expenses:food:eating out      10.95
    expenses:food:icecream        4.15
    liabilities:creditcard

Running your First Command

My most frequently used command is ledger bal. This command validates your ledger file while ensuring that all transactions are balanced. It will output the balance of all accounts that exist in the journal file you specify.

Run the following command from the same directory of your journal file.

$ ledger -f main.journal balance

The output displays some important concepts and features of ledger-cli.

The first thing you might notice is that our income account is showing a negative amount. This is expected. Double-entry account necessitates that all transactions must balance. When money leaves one acount (a debit) it must be shown to enter another acount (a credit). In this case your income is paid by your employer and is therefore being debited from their account into your savings account.

Another important thing to draw attention to is how rollups work in ledger-cli. You can see this happening in the assets and expenses accounts. Each account can have many sub-accounts which allow you to categorize your transactions as specfically as you need to without losing the ability to see balances in the higher-level super-accounts. In this example output, we can see that we spent $10.95 on eating out and $4.15 on ice cream for a total of $15.10 on food. Additionally we can see that we have spent a total of $20.10 on expenses as a whole.

Using Ledger for Reporting

Above we showed perhaps the most basic command, but ledger is capable of quite a bit more. Peaking at the manual can be overwhelming, but it is incredibly detailed on the capabilities of ledger.

After a while you might find that your balance report becomes so large that it is difficult to skim to find what you want. Ledger makes filtering reports easy. Try running the following command:

$ ledger -f main.journal balance ^expenses

This command will filter out all other accounts except the expense account and it’s sub categories. What if you’re feeling guilty and don’t want to see ice cream spending on your report? You could show all expenses except iceream with the following command:

$ ledger -f main.journal bal ^expenses and not ^expenses:food:icecream

What if you need more detail than what the balance command provides? For example, what if we want to see line-by-line detail of all expenses? For this you will want to use the register command.

$ ledger -f main.journal register ^expenses

Ledger also has datetime awareness for filtering and grouping transactions. Below we can see ledger grouping our expenses by week.

$ ledger -f main.j reg ^expenses --weekly

To see spending by day of week, try replacing the --weekly flag with --dow.

Summary

The above examples should be just enough to give you a taste of how ledger-cli can be used. If it has piqued your interest, I would suggest modifying the examples with your own budgeting data and begin diving into the ledger docs to see what the tool is capable of.

I am still in the process of dialing in my workflow, but it has involved scripting and configuration of my journal files to get it even close to meeting my needs. Some of the features and pieces of my workflow not discussed in this post include:

  • automating transaction imports
    • scripting the transaction imports
    • matching transactions to accounts
  • validating account names
  • protecting your data
    • using source control
    • encrypting your sensitive data
  • organizing your ledger files
  • budgeting with ledger

I hope to cover these high-level ledger topics in an upcoming post. ⤧  Previous post A Toolbox For Staying Positive at Startups