{#snippet signed(value: number)} 0} class:negative={value < 0}>{amount(value)} {/snippet} {#snippet swatch(id: number | null)} {/snippet} {#snippet rowActions(label: string, edit: () => void, remove: () => void)} {/snippet}
Personal finance
Net worth · {totalAccounts.length} accounts
{@render signed(total)}
Spendable
{@render signed(total - invested)}
Invested
{@render signed(invested)}
Net this month
{@render signed(monthNet)}
Recurring / month
{@render signed(Math.round(monthlyRecurring))}
Projected {dateLabel(projection[0].points.at(-1)?.date ?? data.today)}
{@render signed(projectionEnd[0])}
{importNotice}
{/if}Actual balances through today, then the projection.
Includes future dated transactions and estimates{data.projectionSettings ?.includeRecurring !== false ? ', plus recurring monthly equivalents from next month' : ''}. {data.projectionSettings?.investmentAccountId ? `The selected investment account and new contributions use a hypothetical ${data.projectionSettings.annualReturnPercent}% annual return.` : `Excess above ${amount(data.projectionSettings?.reserveCents ?? 100000)} moves into a projected investment balance with a hypothetical ${data.projectionSettings?.annualReturnPercent ?? '5.00'}% annual return.`} Contributions move money between spendable and invested balances. Enter an item only once across transactions, estimates, and recurring items to avoid counting it twice.
Select accounts to filter transactions.
Add an account or import your transactions to get started.
{/if}{filtered.length} of {data.transactions.length} entries
| Date | Description | Account | Amount | Actions |
|---|---|---|---|---|
| {dateLabel(row.date)} | {row.description}{#if row.source !== 'manual'}
| {@render swatch(row.accountId)}{accountName(row.accountId)} | {@render signed(row.amountCents)} |
No matching transactions.
{/if}{#if filtered.length > 25}{@render signed(Math.round(monthlyRecurring))} per month now. Feeds the projection when enabled.
Rent, subscriptions, salary and other known repeats.
{/if}Dated income and costs you expect.
Add expected costs or income to look ahead.
{/if}Meter readings and estimated variable cost.
Add at least two readings to calculate usage.
{/if}Uses the first and last readings in the billing period, the current unit rate and prorated monthly advances. Fixed charges, taxes and settlements are not included.
Cumulative cost by priority tier.
{unpricedWishes} unpriced {unpricedWishes === 1 ? 'item is' : 'items are'} excluded from these totals.
{/if} {#if data.wishlist.length}Nothing on your wish list yet.
{/if}{amount(Math.round(monthlyInsurance))} per month in premiums.
Add policies to keep track of what is covered.
{/if}{form.message}
{/if}Delete {active.name}? This cannot be undone.
{:else if mode === 'import'}
Upload your CSV or tab-separated export with date, account, description, amount
columns, a Revolut statement export (only completed EUR rows are imported, fees included), or
Knab exports. Knab files go to the account with that IBAN; pick an account to merge several Knab
accounts (current + savings) into one, and transfers between them are left out. Dates like
Fri 1 Aug 2025
and amounts like -€1,234.50 are supported. Empty rows are skipped, and entries appear
in date order. “Start balance” rows import as transactions, so leave those accounts’ opening balances
at zero. New account names are created automatically. Rows already imported, or already entered
with the same amount within a day, are skipped.