YNAB style finances with hledger
. Uses double entry accounting with envelope budgeting.
This document is heavily inspired by the YNAB 4 Rules. This method has kept my money in a good place for a long time:
- Give Every Dollar a Job
- Embrace Your True Expenses
- Roll With The Punches
- Age Your Money
Split your journal files into yearly files, with current.journal
pointing at the current year:
<current-year>.journal
current.journal -> <current-year>.journal
Once you get enough years, make an all.journal
file that includes every year so you can do historical analysis.
$ cat all.journal
include 2021.journal
include 2022.journal
Because this is an adaptation of envelope budgeting there are some account prefix conventions that should be observed:
assets:cash
- This is any cash or cash equivilents you posess. I don't track actual cash once it leaves my bank account, so this is basically money in a bank account.assets:cash:<account>:checking
andassets:cash:<account>:savings
- This is checking and savings for a single bank account. I only have one bank, so mine isassets:cash:ally:checking
. This is where paychecks go when I get paid. More on this next.assets:cash:<account>:budget:checking|savings:<category>
- These are envelopes where spendable money goes. This is where all spendable money goes. This means that your actual checking and savings accounts should have a zero balance in your ledger. When you add up the budget categories in yourbudget:checking:*
accounts, it should add up to the amount in your physical checking account. This way you can never overspend your balance as long as you follow your envelopes. It is a bit deceiving, but it's good for tracking!assets:cash:<account>:budget:checking|savings:unallocated
- This is money that you don't have a job for yet. All money needs a category, even if it's not assigned yet.assets:cash:<account>:budget:checking|savings:pending:<credit-card>
- This is money that is set aside to pay a credit card. Whenever you buy something on a credit card, you'll transfer money from your budget envelope to this account. This ensures that you always have enough money to pay your credit card at the end of the month. It's scoped to checking or savings so that you can keep track of where to pay from. It's probably pretty rare to pay a credit card from a savings account, so I'd expect this to only be a checking sub-account. Doing this also lets you reconcile yourassets:cash:<account>:budget:checking
account with your actual checking balance. If you runhledger bal <account>:budget --cleared
, this number should match your physical bank balance.
These follow standard hledger
conventions: liability:<name>
, where name is a descriptor for the credit card, loan, etc.
These follow standard hledger
conventions: expenses:<name>
, where name is a descriptor for the expense type. I find it useful to match your budget category names.
So how do we use the 4 rules with hledger
?
This means when you receive income, every cent that you received should be assigned an account category.
For regular job income I record net received, not the gross. Taxes and such are "invisible" in this case. It also means any retirement transfers that are pre-tax do not show up from income. We'll cover that later.
I get paid on the 1st and 15th of the month.
2021-12-01 Paycheck
assets:cash:ally:checking $1000
income:salary
Note that this violates on of the rules stated above: money never actually sits in a physical checking account, it must be assigned a job. So if you know what job all your money has immediately, send the money to those accounts. Otherwise, put it in the unassigned
account:
2021-12-01 Budgeting
assets:cash:ally:budget:checking:mortgage $600.00
assets:cash:ally:budget:checking:utilities $100.00
assets:cash:ally:budget:checking:groceries $100.00
assets:cash:ally:budget:checking:unallocated $200.00
assets:cash:ally:checking = 0
Note the balance assertion
at the end of this. This ensures that you moved all your money into budget categories.
To ensure you did this correctly, you can use hledger bal -BEt assets:cash
to check. assets:cash:ally:budget:checking
should equal the actual amount in your bank account at that time. assets:cash:ally:checking
should be 0
.
Now that your money has a job, you can spend it!
2021-12-14 People's Gas
expenses:utilities $96.04
assets:cash:ally:budget:checking:utilities
Now when you check your balances with hledger bal -BEt budget:utilities
you'll see that you have $3.97 left to spend. This amount will stay there forever until you move, add to it or spend the remaining. This transaction was pretty simple because usually you'll pay your utilities from your checking account. But what about paying with a credit card?
2021-11-27 Amazon
expenses:groceries $3.41
assets:cash:ally:budget:checking:groceries $-3.41
assets:cash:ally:budget:checking:pending:amazon-visa $3.41
liabilities:amazon-visa
This is a little more complicated, there's 4 postings! This is explained by:
- Add to the expenses category
- Subtract from the budget category
- Add to the appropriate credit card pending account so we have money to pay
- Subtract from the credit card because we owe more money
The assets:cash:ally:budget:checking:pending
account is meant to hold money to pay credit cards. In this way, you can never overspend your credit card and not have enough money to pay it. So let's pay it now:
2021-12-30 Visa Payment
assets:cash:ally:budget:checking:pending:amazon-visa $-3.41
liabilities:amazon-visa = 0
Another balance assertion
to make sure we're paying the full amount of the card.
This is heavily related to Rule 1
. The gist is that you want to find large expenses like car insurance, christmas gifts, capex for real estate, etc and put small amounts of money to them every month. So if you know that you have a $600 car insurance payment every 6 months, make sure you put $100 into that budget category every month.
This means when you overspend a category, don't fret! It's normal. Simply move money from another category that has an abundance to the negative one. If you have extra money in unallocated
, this is the best place to start:
2021-11-28 Budget Transfer
assets:cash:ally:budget:checking:spending-money:me $43.17
assets:cash:ally:budget:checking:unallocated
If you have no money in the unallocated category, it needs to come from another category (or more than one)
2021-11-28 Budget Transfer
assets:cash:ally:budget:checking:spending-money:me $43.17
assets:cash:ally:budget:checking:groceries $-20.00
assets:cash:ally:budget:checking:fuel $-23.17
The gist of this rule is that you want to have at least one month's expeses in reserve. Another way to put it is that the average age of money in your bank account should be 30 days old.
I haven't figured out how to calculate this in hledger
yet, but I am pretty sure it's possible!
Okay, so how to do other things?
- Subtract from the budget category
- Add interest expense (we pay money for the loan)
- Add escrow expense (if there is one)
- Add remaining amount to loan liability (we owe less to the bank)
2021-11-28 Mortgage
assets:cash:ally:budget:mortgage $-1,000.00
expenses:interest:mortgage $100.10
expenses:escrow:mortgage $225.00
liabilities:mortgage
We got paid from amex directly to our amex balance
- Add the amount to our amex liability (we owe less)
- Add the amount to our unallocated budget (or another one if you know where it could go) (we have more to spend)
- Remove the amount from our pending amex payment (we don't have to pay amex as much)
- Remove the amount from the income account where the payment came from
2021-11-26 AMEX | Dining Credit
liabilities:amex $10
assets:cash:ally:budget:unallocated $10
assets:cash:ally:budget:checking:pending:amex $-10
income:amex
For things like a 401k or HSA that comes out of income pre-tax by the employer, you can still record that as income (since it is: you would have received cash and then transfered the funds anyway). These don't involve budgets though.
2021-11-26 401k contribution
assets:investments:401k 314.5 VTSAX @ $114.65
income:401k
If you receive an employer match and want to record that, use two income lines:
2021-11-26 401k contribution
assets:investments:401k 314.5 VTSAX @ $114.65
income:401k:match $-500.00
income:401k
I budget money for after-tax investments, so it's basically a normal transaction except you trade USD for another asset minus fees.
2021/11/26 Coinbase
assets:investments:coinbase 30.700514 ADA @ $1.56
expenses:fees:coinbase $1.99
assets:investments:coinbase 0.0175312 ETH @ $4,107.53
expenses:fees:coinbase $2.99
assets:investments:coinbase 0.00131575 BTC @ $54,729.24
expenses:fees:coinbase $2.99
expenses:fees:coinbase $0.12 ; Rounding
assets:cash:ally:budget:checking:investing:crypto $-200.00
- Add the payment amount to your liability account (you paid the debt)
- Subtract the payment amount from
assets:cash:<account>:budget:checking:pending:<card>
(you're sending money from your checking account to pay the debt)
2021-11-29 Amex Payment
liabilities:amex $1,234.56 = 0
assets:cash:ally:budget:checking:pending:amex $-1,234.56 = 0