In terms of geekiness, I believe I’ve hit a new low. This post is going to be about how we now manage our finance using “Plain text accounting.”
With hledger we can write our accounting data in human readable plain text files, and later get reports out of them, or query the data as we desire. A big bonus is that since our file is in plain text, it can be version controlled.
On top of that hledger is written in Haskell. What more can a geek ask for!
In this post I will explain what our needs are, what were the solutions we went with until not long ago, and how we setup hledger to give us the answers we needed. I suspect most readers that run a web shop business will find a lot of similarities. So it’s likely our setup will be a good base for you as-well.
We have a few uses for hledger, but the most time consuming is forecasting and cash flow. Unlike registering transactions that happened in the past, and as such are carved in stone - when it comes to forecasting, it’s a moving target. Clients don’t always pay exactly on time, credit charges can change, and from time to time – as in real life – there’s some surprise that you didn’t expect.
We use forecasting to know when to move money from one bank to another; When and how much we can put aside, or when to keep cash liquid. Up until now we were either using some homegrown spreadsheets and/or some SASS solution such as PulseApp.
Spreadsheets are powerful, and without too much effort, we can build the sheets to show the info we want, the way we want it. Furthermore it’s free (Google Sheets), and can be shared easily among several collaborators. However, with great power comes great responsibility: once the table becomes bigger, as it did, it was hard to track mistakes.
As we’re dealing with forecasting, we have to move rows from one place to
another quite frequently. With formulas in place, it often caused some nasty
#VALUE! errors. Forecasting by nature is “playing” with future data, and finding
the best timeline for each transaction we control. So once we moved items, we
sometimes wanted to go back to the initial state. Clicking “undo” several times isn’t
robust and it’s error prone.
SASS products like PulseApp are surely a good solution for non-tech people. We can setup all our different accounts and currencies, have a nice UI to enter our data, and we may even enjoy the animated graphs presented to us. However, very much like with spreadsheets, moving several items together from one date to another requires a bunch of clicks – and undoing this is just as tedious. No undo button.
Furthermore, with spreadsheets, you can duplicate the sheet before any big change, and try it out there, but then if you are not careful, it’s so easy to end up with a “Forecasting & Cash flow-Final-Final-Final” version. It’s even worse with SASS solutions where “branching” is not an option at all.
When I don’t run my business, take care of finances, and do some boring paper work that comes with the job - I’m a developer: one that loves Git, one that is not afraid of the command line, and one that often thinks “there must be a better way.”
Having worked with hledger for some time now, I believe that the “better way” was in fact already implemented, and it immediately made my life better. It’s easier for me to edit my data. It’s easier for me to keep track of what was changed. And it’s easier for me to answer questions I always used a bit of gut feeling to answer, instead of hard data.
I’d like to share the important parts of how we structure our ledger to get the info we need. First a bit of background for our operation. Gizra has two main hubs. One in Israel, just because. And the second in the US, for the obvious reasons. We have clients, we have employees, we have several credit cards using different currencies, we have payments to settle, and we have payments to charge.
We also have 3 banks accounts. Here are their anonymized details:
- Bank of America (BOA) in the US just has a USD account.
- Bank of Israel (BOI) has both an ILS and a USD account.
- Bank of Jerusalem (BOJ), also have an ILS and USD accounts, but it’s hardly used. Some credit cards are still connected there, so we need to keep an eye there once a month.
To sum up our needs:
- We’d like to know about the state of Banks 1 and 2, on a daily basis. That’s where our business lives.
- Once a month, we’d like to check that the balance in Bank 3 is also fine. Nothing dramatic should happen there.
Here’s the repo with the code, and lots of comments in the ledger file.
We start the UI version of hledger, giving it the file name to open, and
--watch to keep it updating as we change the file.
hledger-ui -f hledger.journal --watch
When clicking on the right arrow we drill down. In this case we’ve drilled into
assets:banks:israel:boi:ils - so it’s no surprise we see all the values in ILS.
Clicking on the left arrow gets us back to the overview page. Doing currency
conversions in my head is hard, so with hitting
V (shift + V) hledger
does the conversion for me.
It knows how to do it, because in our ledger file we tell it the conversion rate.
Also, you would notice in the screenshots we added commodities called
USD:[BANK NAME], to make sure hledger will
show us the funds in each bank, without consolidating everything under a single USD value. This is the trick that
allows us to see the state of several banks in a single line.
But having to drill down to each bank on its own, doesn’t answer our needs. We need
to see all the bank amount side by side. This is where the
: divider comes in.
It’s actually the hierarchy. So by hitting
2, we tell hledger that we want it to
collapse and group all the
And once again, hitting
V will show us the sum of all banks, in ILS (you would
probably use a different currency - the one your brain works with more naturally).
Drilling down at this state of “depth 2”, means we can see all the transactions of both BOA and BOI banks, and the value of each bank after each transaction. So far everything seems fine, and nothing is in the red.
Lets see what’s ahead of us in the future. Hitting
F reveals we have some problem.
Our BOA account is going to be -$600.
Does it mean our entire operation is at risk since we have no funds? Hitting
shows us that’s not the case. All our assets together are +7,215 ILS. So in terms
of planning, we know we should have a wire transfer from our ILS account to the US
But what about those “ancillary” accounts? How do we get them to be shown along
with the other banks? Since their name is
assets:banks-ancillary, having depth 2
will still keep them separated.
For this we can use the
--alias option, like so:
hledger-ui -f hledger.journal --watch --alias=assets:banks-ancillary=assets:banks
Now, hledger gets us all our banks together.
V, we can see all our assets converted to a single currency.
hledger has proven itself to allow us to get data quicker than before. We wanted to issue a couple of new credit cards, and we wanted to get a sense of how much we spend per month. I kind of know the number, just from being around for so long, but I was happy to realize I could now do something like:
hledger balance -f hledger.journal liabilities:israel:cc --monthly -V -3
Asking hledger to get us the
liabilities:israel:cc, per month,
and collapse it to depth of 3:
Balance changes in 2019/11/01-2019/12/31, valued at period ends:
|| Nov Dec
liabilities:israel:cc || ILS 23,250.00 ILS 25,000.00
|| ILS 23,250.00 ILS 25,000.00
Now that all our accounting is version controlled, creating Git branches and pull requests are the next obvious step. But we could even go one step further and add some automated integration. Here is the GitHub Actions configuration we’ve added in our accounting repo. It confirms on each push that the ledger file is valid. If it’s not, we’d know about it in less than 10s.
Below is a Slack message I’ve sent in our devs channel when I just came across hledger.
I’m happy I’ve decided to stick around beyond my first reaction of not having
a “proper” UI. While hledger does in fact have a Web version, I found the
hledger-ui more robust.
In the end, it took me only a couple of days, of having worked on both spreadsheets and hledger in parallel, before having full confidence that hledger is the solution we were seeking for. I’m not missing our spreadsheets at all.
For anybody comfortable with Git and command line, and with similar needs, I encourage you to have a look. Not only are the docs on the site great, but also the IRC room is very active, and Simon Michael - the author of hledger - was helping me out with figuring out all the smaller details to get it right.