Put future-dated transactions in a separate scenario ledger to project cash, expenses, and debt in your financial reports. This walkthrough uses ordinary Beancount entries and a fixed planning period. Your realized books stay separate from your assumptions.
Compatibility, checked September 7, 2026: the examples were tested with stock Beancount 3.2.3, beanquery 0.2.0, and Fava 1.30.16. That Fava release does not ship a forecast plugin. Beancount.io's custom source does contain a fava.plugins.forecast implementation; that is a different runtime, and source availability does not establish the version deployed to your account. The portable workflow below needs no extension.
Step 1: Enable the Forecast Plugin
Skip plugin activation for this workflow. Adding plugin "fava.plugins.forecast" to the tested stock installation produces an import error. For general plugin setup, see the plugin guide; a module must actually be installed before a ledger can load it.
Prerequisites: a local Python environment with beancount==3.2.3, beanquery==0.2.0, and fava==1.30.16 installed. Follow the pinned Fava setup to create that environment. Save all three files below in the same directory, and run the commands there.
Create books.beancount with this complete example snapshot. Its as-of date is December 31, 2023, after the opening transaction. Checking holds 10,000.00 USD and the outstanding car-loan principal is 14,400.00 USD. Equity balances this simplified opening snapshot.
; books.beancount — realized balances as of 2023-12-31
option "operating_currency" "USD"
2023-12-31 open Assets:Checking USD
2023-12-31 open Liabilities:Auto-Loan USD
2023-12-31 open Equity:Opening-Balances USD
2023-12-31 open Income:Salary USD
2023-12-31 open Expenses:Housing:Rent USD
2023-12-31 open Expenses:Food:Groceries USD
2023-12-31 open Expenses:Health:Gym USD
2023-12-31 open Expenses:Insurance:Auto USD
2023-12-31 open Expenses:Transportation:Interest USD
2023-12-31 * "Opening snapshot"
Assets:Checking 10000.00 USD
Liabilities:Auto-Loan -14400.00 USD
Equity:Opening-Balances 4400.00 USDCreate scenario.beancount as the planning entry point. Its two includes load the realized snapshot and the assumptions you will write next. Beancount reads the include paths relative to this file.
; scenario.beancount — planning entry point
option "title" "January 2024 planning scenario"
option "operating_currency" "USD"
include "books.beancount"
include "scenario-2024-01.beancount"Never include scenario.beancount or scenario-2024-01.beancount from books.beancount. The realized entry point must not load planned transactions, even after their dates pass.
Step 2: Create a Forecast Transaction
Create scenario-2024-01.beancount with this first entry. Append the four later scenario blocks to that same file once each. These are contextual transaction blocks: their account declarations come from books.beancount, and you validate them through scenario.beancount.
2024-01-01 ! "Scenario: January rent" #forecast
Expenses:Housing:Rent 2500.00 USD
Assets:Checking -2500.00 USDThe ! flag marks a transaction for review; #forecast is an ordinary transaction tag. Neither creates recurrences or excludes a transaction from reports. The separate entry point controls inclusion. Use this tag only on planned entries so that you can identify them during review.
Understanding the Forecast Syntax
Every dated entry represents one occurrence. Narration text such as [MONTHLY] has no recurrence effect in stock Beancount. The older UNTIL, REPEAT, and SKIP instructions belong to a custom plugin convention, not the core language. This workflow expresses their intended dates explicitly.
The scenario covers January 1–31, 2024, inclusive. All planned dates are after the fixed as-of date and before February 1. These historical dates make the example reproducible; nothing depends on today's date. When adapting it, choose a new as-of date and finite horizon before adding entries.
Frequency
Write one transaction for each due date inside the planning period. The complete January example uses these rules:
| Item | Schedule | Dates included in January 2024 |
|---|---|---|
| Rent | Monthly, on the 1st | January 1 |
| Groceries | Every 7 days, starting January 1 | January 1, 8, 15, 22, 29 |
| Salary | Every 14 days, starting January 5 | January 5, 19 |
| Gym | Monthly, on the 15th | January 15 |
| Loan payment | Monthly, on the 25th | January 25 |
| Car insurance | Every 3 calendar months, starting January 15 | January 15; next payment April 15 is outside this horizon |
For other daily or yearly plans, enumerate the actual due dates in the same way. Set a policy for dates such as the 31st or February 29 before extending a schedule. Do not silently move them or assume every month has the same number of days.
Conditions (Optional)
1. Set an end date explicitly
Suppose the gym membership ends on December 31, 2024. Its January occurrence is below. The January scenario stops at January 31, so it contains no February–December entries. If you extend the horizon, write each later payment through December 15 and stop there.
2024-01-15 ! "Scenario: gym membership" #forecast
Expenses:Health:Gym 80.00 USD
Assets:Checking -80.00 USD2. Limit occurrences and separate loan principal from interest
Suppose the car loan has 36 remaining payments. Include only the first payment in this January horizon. For this hypothetical installment, assume its 450.00 USD cash payment consists of 400.00 USD principal and 50.00 USD interest. These are scenario assumptions; no later installments are generated.
2024-01-25 ! "Scenario: car loan payment 1 of 36" #forecast
Liabilities:Auto-Loan 400.00 USD
Expenses:Transportation:Interest 50.00 USD
Assets:Checking -450.00 USDThe positive liability posting reduces the debt balance from −14,400.00 USD to −14,000.00 USD. Cash falls by 450.00 USD, and only 50.00 USD is an expense. The postings balance because 400.00 + 50.00 - 450.00 = 0. A negative liability posting would increase the debt.
Do not repeat the same principal/interest split for all 36 payments without a supporting schedule. Future interest and the final payment can differ. Use the lender's payment schedule when extending this example; see amortization for the distinction between expense recognition and debt repayment.
3. Write irregular intervals as actual dates
For a biweekly salary starting January 5, the January dates are January 5 and January 19. The next occurrence is February 2, outside this scenario. Biweekly means every 14 days, not twice per calendar month.
2024-01-05 ! "Scenario: salary" #forecast
Assets:Checking 3000.00 USD
Income:Salary -3000.00 USD
2024-01-19 ! "Scenario: salary" #forecast
Assets:Checking 3000.00 USD
Income:Salary -3000.00 USDPractical Example: A Monthly Budget
Complete your monthly budget by appending the groceries and car-insurance entries below to scenario-2024-01.beancount. Together with rent, gym, the loan payment, and both salary entries above, this produces 11 planned transactions.
2024-01-01 ! "Scenario: groceries" #forecast
Expenses:Food:Groceries 150.00 USD
Assets:Checking -150.00 USD
2024-01-08 ! "Scenario: groceries" #forecast
Expenses:Food:Groceries 150.00 USD
Assets:Checking -150.00 USD
2024-01-15 ! "Scenario: groceries" #forecast
Expenses:Food:Groceries 150.00 USD
Assets:Checking -150.00 USD
2024-01-22 ! "Scenario: groceries" #forecast
Expenses:Food:Groceries 150.00 USD
Assets:Checking -150.00 USD
2024-01-29 ! "Scenario: groceries" #forecast
Expenses:Food:Groceries 150.00 USD
Assets:Checking -150.00 USD
2024-01-15 ! "Scenario: quarterly car insurance" #forecast
Expenses:Insurance:Auto 450.00 USD
Assets:Checking -450.00 USDValidate both entry points, then query their closing balances. date < 2024-02-01 includes all January postings. The books query uses the fixed as-of boundary date < 2024-01-01.
bea --file books.beancount check
bea --file scenario.beancount check
bea --file books.beancount query "SELECT account, sum(position) WHERE date < 2024-01-01 GROUP BY account ORDER BY account"
bea --file scenario.beancount query "SELECT account, sum(position) WHERE date < 2024-02-01 GROUP BY account ORDER BY account"Both bea check commands exit 0 when clean; errors are listed with a non-zero exit. Reconcile the query results against these independent calculations:
| Result | Realized books, December 31 | January scenario, January 31 |
|---|---|---|
| Checking | 10,000.00 USD | 10,000 + 6,000 − 2,500 − 750 − 80 − 450 − 450 = 11,770.00 USD |
| Loan balance | −14,400.00 USD | −14,400 + 400 = −14,000.00 USD |
| Salary income posting | 0.00 USD | −6,000.00 USD |
| Total expense postings | 0.00 USD | 2,500 + 750 + 80 + 450 + 50 = 3,830.00 USD |
January's projected profit is 2,170.00 USD: 6,000 income less 3,830 expenses. Checking increases by 1,770.00 USD because the additional 400 principal repayment reduces debt rather than profit.
Open the scenario in stock Fava:
fava scenario.beancountSet Fava's Time filter to 2024-01. Its time filtering carries prior asset and liability balances into the period and removes later entries. Check the balance sheet for 11,770.00 USD cash and 14,000.00 USD outstanding debt. The income statement should show 2,170.00 USD projected profit. Opening books.beancount instead gives the realized snapshot.
Troubleshooting & Best Practices
- Import error for the old plugin: remove the activation line when using this portable workflow. A stock Fava installation does not provide Beancount.io's custom modules.
- Unknown account or missing include file: save all three files in the same directory, copy the opens, and validate
scenario.beancountrather than the scenario fragment alone. - Forecasts missing from Fava: load
scenario.beancountand set the Time filter to2024-01. A tag or narration does not generate entries. - Unexpected balances: compare the 11 planned dates and amounts with the table. Loading an occurrence twice doubles its financial effect, even when every transaction balances.
- Keep forecasts separate: ordinary flags, tags, and future dates do not prevent entries from affecting an unfiltered report. Use
books.beancountfor actual results. When a payment happens, record its actual amount there and remove the corresponding assumption from your next scenario to avoid counting it twice. - Review the horizon: preserve a dated snapshot when saving a scenario. Extending its end date means adding specific occurrences and checking loan splits, cancellation dates, and rounding again.