Introduction
In the United States, retirement accounts are specialized investment vehicles designed to support long-term financial security during post-employment years. These accounts—primarily Individual Retirement Accounts (IRAs) and employer-sponsored plans such as 401(k)s—offer significant tax advantages to incentivize consistent saving. The Internal Revenue Service (IRS) sets and periodically adjusts contribution limits for these accounts to account for inflation.
Given their unique regulatory and tax characteristics, retirement accounts differ from standard brokerage or investment accounts. When documenting them in Beancount, a plain-text double-entry accounting system, a structured approach is necessary to track both contributions and IRS-imposed limits.
The Beancount example in this post can be found in: https://github.com/flyaway1217/beancount_example/blob/main/single_examples/real_estate.bean
In this guide, we cover:
- Recording contributions to pre-tax and Roth 401(k) plans, including employer matching. (This guide can be easily extended to IRA accounts)
- Tracking annual contribution limits in compliance with IRS rules.

401K Tables
Account Structure
To effectively record retirement contributions in Beancount, we track two primary elements:
- Contributions made throughout the year.
- Remaining contribution allowances based on IRS limits.
As shown in the figure above, 401(k) accounts are generally divided into two parts1:
- Elective Deferrals: Includes both pre-tax and Roth 401(k) contributions, subject to the elective deferral limit ($23,000 in 2024).
- After-Tax Contributions: Additional after-tax contributions subject to the overall annual limit ($69,000 in 2024).
To reflect these constraints, we define two quota-tracking commodities and three holding accounts. While real-world scenarios may require more granular asset categorization, this post adopts a simplified structure.
Commodity and Account Declarations
; Define commodities
2024-01-01 commodity USD ; Operating currency
2024-01-01 commodity ED401K ; Elective deferral quota
2024-01-01 commodity TOTAL401K ; Total 401K limit
2024-01-01 commodity VINIX ; Example investment instrument
; Define quota-tracking accounts
2024-01-01 open Assets:Retirement:401K:ElectiveDeferral:Quota ED401K
2024-01-01 open Assets:Retirement:401K:Quota TOTAL401K
; Define contribution cash accounts
2024-01-01 open Assets:Retirement:401K:Cash:PreTax:Vanguard USD
2024-01-01 open Assets:Retirement:401K:Cash:Roth:Vanguard USD
; Define investment holdings
2024-01-01 open Assets:Retirement:401K:ElectiveDeferral:PreTax:Vanguard:VINIX VINIX
2024-01-01 open Assets:Retirement:401K:ElectiveDeferral:Roth:Vanguard:VINIX VINIX
2024-01-01 open Assets:Cash:Checking:Chase USD
; Define expenses accounts
2024-01-01 open Expenses:Taxes:Retirement:401K:ElectiveDeferral ED401K
2024-01-01 open Expenses:Taxes:Retirement:401K:Total TOTAL401K
2024-01-01 open Expenses:Taxes:Retirement:401K:ElectiveDeferralUnused ED401K
2024-01-01 open Expenses:Taxes:Retirement:401K:TotalUnused TOTAL401K
2024-01-01 open Expenses:Finance:FinancialFees USD
; Define income accounts
2024-01-01 open Income:Work:Employer:Earnings:Regular USD
2024-01-01 open Income:Work:Employer:Benefits:401KMatch USD
2024-01-01 open Income:Benefits:Federal:401K
Recording Contributions
Payroll Deductions
401(k) contributions are typically deducted directly from payroll:
2024-01-30 * "Employer" "Salary"
; Gross income
Income:Work:Employer:Earnings:Regular -8,787.19 USD
; Tax
; ...
; Pre Tax Deductions
Assets:Retirement:401K:Cash:PreTax:Vanguard 483.30 USD
; ...
; Post Tax Deductions
Assets:Retirement:401K:Cash:Roth:Vanguard 483.30 USD
; ...
; Direct deposit
Assets:Cash:Checking:Chase 7,820.59 USD
This entry reflects a total of $966.60 in contributions—equally split between Roth and pre-tax 401(k) accounts.
Employer Match
Employer-matched contributions, always categorized as pre-tax, can be recorded as follows:
2024-01-30 * "Employer" "401K Match"
Income:Work:Employer:Benefits:401KMatch -483.30 USD
Assets:Retirement:401K:Cash:PreTax:Vanguard 483.30 USD
I divide the Employer income into Benefits
and Earnings
to separate the
regular income and the benefits, trying making it more clear.
Investment Transactions
To record investments made from the 401(k) cash balance into a specific fund (e.g., VINIX):
2024-01-30 * "Vanguard" "Investing Pre-Tax 401K"
Assets:Retirement:401K:Cash:PreTax:Vanguard -966.60 USD
Assets:Retirement:401K:ElectiveDeferral:PreTax:Vanguard:VINIX 2.203 VINIX {438.78 USD}
Expenses:Finance:FinancialFees
2024-01-30 * "Vanguard" "Investing Roth 401K"
Assets:Retirement:401K:Cash:Roth:Vanguard -483.30 USD
Assets:Retirement:401K:ElectiveDeferral:Roth:Vanguard:VINIX 1.101 VINIX {438.78 USD}
Expenses:Finance:FinancialFees
Tracking Contribution Limits
To monitor IRS-imposed contribution limits, we use the two quota commodities: ED401K
and TOTAL401K
.
Initializing the Quota
At the beginning of each tax year, initialize your annual quotas:
; At the beginning of each year, we initialize the limits
2024-01-01 * "Initialize 401K Quota for 2024"
Assets:Retirement:401K:ElectiveDeferral:Quota 23,500 ED401K
Assets:Retirement:401K:Quota 70,000 TOTAL401K
Income:Benefits:Federal:401K
These represent your eligibility to contribute and are treated as Assets
in
the ledger. In the preceding example, we establish these two asset accounts
representing the annual contribution limits for 401(k) plans as stipulated by
the IRS. These accounts are recorded as Assets
, reflecting our entitlement to
contribute up to these limits. Each time a contribution is made to a 401(k)
account, we correspondingly transfer the same amount from the respective asset
account to an expense account. This accounting treatment allows us to monitor
both the utilized portion of our contribution limits (via the Expenses
accounts) and the remaining available limits (via the Assets
accounts) for
the current tax year.
Quota Deductions
Both the pre-tax 401(k) and Roth 401(k) are subject to the elective deferral limits and total 401(k) limits. To accommodate this, amend your payroll transaction to deduct from quota accounts as follows:
2024-01-30 * "Employer" "Salary"
; Gross income
Income:Work:Employer:Earnings:Regular -8,787.19 USD
; Tax
; ...
; Pre Tax Deductions
Assets:Retirement:401K:Cash:PreTax:Vanguard 483.30 USD
; ...
; Post Tax Deductions
Assets:Retirement:401K:Cash:Roth:Vanguard 483.30 USD
; ...
; Direct deposit
Assets:Cash:Checking:Chase 7,820.59 USD
; Track ElectiveDeferral401K
Assets:Retirement:401K:ElectiveDeferral:Quota -966.60 ED401K
Expenses:Taxes:Retirement:401K:ElectiveDeferral 966.60 ED401K
; Track Total401K
Assets:Retirement:401K:Quota -966.60 TOTAL401K
Expenses:Taxes:Retirement:401K:Total 966.60 TOTAL401K
Different from your own contributions, employer contributions affect only the total 401(k) limit:
2024-04-15 * "Employer" "401K Match"
Income:Work:Pinterest:Benefits:401KMatch -483.30 USD
Assets:Retirement:401K:Cash:Vanguard 483.30 USD
Assets:Retirement:401K:Quota -483.30 TOTAL401K
Expenses:Taxes:Retirement:401K:Total 483.30 TOTAL401K
Resetting Quotas at Year-End
We record the 401(k) contribution limits with each payroll cycle. At the end of
the calendar year, we reset the associated Assets
accounts to reflect the
expiration of unused contribution limits, as per IRS regulations. For the new
year, we initialize the limits based on the updated figures published annually
by the IRS.
To automatically transfer the unused contributions to the Expesnes
, we
utilize the pad
directive provided by the Beancount(more about the pad directive can be found here):
2024-12-31 pad Assets:Retirement:401K:ElectiveDeferral:Quota Expenses:Taxes:Retirement:401K:ElectiveDeferralUnused
2025-01-01 balance Assets:Retirement:401K:ElectiveDeferral:Quota 0 ED401K
2024-12-31 pad Assets:Retirement:401K:Quota Expenses:Taxes:Retirement:401K:TotalUnused
2025-01-01 balance Assets:Retirement:401K:Quota 0 TOTAL401K
The dates for pad
and balance
have to be different.
We examine the year-end quota by looking at the following four accounts:
|
|
Balancing Account Granularity and Filtering Flexibility
Some users prefer to organize expense accounts with detailed granularity by
year, using structures such as
Expenses:Taxes:Retirement:401K:ElectiveDeferral:2024
. While this approach
offers specificity, it can lead to an increasingly complex hierarchy of
subaccounts, which may become cumbersome to manage over time. An alternative
is to utilize Beancount’s Query Language (BQL) or Fava’s filtering
capabilities to isolate transactions by year without modifying the account
structure. For example, in Fava, you can filter entries by specifying the
desired year in the time filter, such as 2024, or by using regular
expressions to match account names. Similarly, BQL allows for queries like:
SELECT account, SUM(position)
WHERE account ~ ".*401K.*" AND date >= 2024-01-01 AND date <= 2024-12-31
GROUP BY account
This method provides flexibility in reporting and analysis without the need to create additional subaccounts. Ultimately, the choice between detailed account hierarchies and dynamic filtering depends on your personal preference and the specific requirements of your financial tracking.
Adapting for IRAs
This methodology can be readily extended to Individual Retirement Accounts (IRAs). Since IRAs are governed by a single contribution limit and lack employer matching, the accounting is even simpler. Only one quota commodity and one set of tracking accounts are needed.
Final Thoughts
Although this system involves several accounts and custom commodities, it provides a comprehensive framework for accurately tracking retirement contributions and IRS compliance. Once incorporated into your routine, it becomes both intuitive and powerful, offering deep insights into your retirement savings strategy.