Real-Time Financial Analytics with Fava and Beancount
Introduction
Beancount is an open-source double-entry accounting system that uses plain text files as the ledger. It emphasizes simplicity, transparency, and flexibility in tracking finances. Fava is a powerful web-based front-end for Beancount, providing an interactive interface for viewing reports, visualizations, and managing your ledger. In this report, we explore the core capabilities of Beancount and Fava, and how to achieve real-time or near-real-time financial analytics with these tools. We cover configuration tips for automation and data refresh, Fava’s visualization features (for instant cash flow views and trend spotting), integration with external dashboards (Grafana, Metabase, etc.), examples of custom dashboards and plugins, use cases in personal and small-business finance, comparisons with other platforms (Power BI, QuickBooks), and the pros/cons of using Fava+Beancount for data-driven insights.
Core Capabilities of Beancount and Fava
Beancount (Plain-Text Accounting Engine)
- Double-Entry Ledger in Plain Text: Beancount stores transactions in a single
.beancount
text file (or multiple files included together). Every transaction must balance (total debits = total credits) across accounts, enforcing accounting integrity. The plain text format means your data is human-readable, version-controllable, and not locked into any vendor. - Flexible, Hierarchical Accounts: You can define any accounts (e.g.
Assets:Bank:Checking
,Expenses:Food:Coffee
) in a hierarchy. Beancount isn’t opinionated about your chart of accounts, so it works for personal finance, small business books, investments, etc. – it’s “flexible: works for personal finance, small business bookkeeping, crypto, stock investments, and more.” - Multiple Currencies and Commodities: Beancount has first-class support for multiple currencies and commodities (e.g. stocks, crypto). You can record transactions in different currencies, define exchange rates (price directives), and track cost bases. It can produce reports “at cost” or “at market value” if price data is provided. This makes it suitable for portfolios and international finance.
- Automated Checks and Balances: The system supports balance assertions (you can declare what an account’s balance should be at a date, and Beancount will error if it doesn’t match) and balance transactions for closing books. It also supports equity opening/closing entries and retains earnings calculation for period closes. These help ensure your books remain consistent and catch errors early.
- Powerful Query & Reporting Engine: Beancount comes with a query language BQL (Beancount Query Language) and command-line tools like
bean-balance
,bean-register
, andbean-query
to generate reports. You can query the ledger for custom reports (e.g. list of expenses by payee, cash flow for a period) – essentially treating the ledger like a database. It’s fast even with thousands of transactions, and can output to CSV or even directly to Excel/LibreOffice (with optional add-ons). - Extensibility via Plugins: Beancount is written in Python and allows custom plugins to extend its functionality. Plugins can enforce additional rules or calculations when the file is processed. (For example, there are plugins to handle tax lots, or to ensure no purchase is missing a cost.) The plugin system and Python API let advanced users script custom behaviors or integrate Beancount with other systems.
- Importers for External Data: A key practical feature is Beancount’s ingest framework for importing data (e.g. from bank statements). You can write or use importer plugins that parse CSV, OFX, PDF statements, etc., and convert them into Beancount entries. This is essential for automation (more on this later).
- Auditable and Version-Control Friendly: Because it’s plain text, you can keep your ledger in Git or other version control. Every change is transparent, and you have a full history of edits. This makes audits or reviewing changes straightforward (many users commit each day’s changes to a Git repo, providing a tamper-evident log of all financial entries). This level of transparency is a major differentiator from closed accounting software – “no SaaS lock-in—just clean, transparent accounting with powerful reporting.”
Fava (Web Interface for Beancount)
- Interactive Web UI: Fava provides a local web server that renders your Beancount ledger into a rich UI. It displays core reports (Income Statement, Balance Sheet, etc.), account registers, and journals in the browser with interactive controls. The UI is dynamic and user-friendly compared to the command line. You start it with a simple
fava yourfile.beancount
and get a web app for your books. - Graphs and Charts Built-In: Fava generates graphs to help visualize your data. For example, it includes a Net Worth line chart over time, bar charts for income vs. expenses per month, and pie/treemap charts for expense breakdowns. These visuals update with your data and support different views (e.g. “at cost” vs “market value” for investments). We’ll explore these visualization capabilities in detail later.
- Filtering and Search: At the top of Fava’s pages, a filter bar lets you slice and dice your data in real-time. You can filter by time (e.g. year, quarter, month), by account regex, by payee, by narration, or by tags/links. This makes it easy to do real-time data inspection – for example, quickly filter to “Tag=Travel” and “Year=2025” to see all travel expenses in 2025, with totals. The interface supports complex queries through this filter bar or via the Query page (where you can directly execute BQL queries).
- Multiple File Support and Consolidation: Fava can load multiple Beancount files at once (useful if you separate ledgers) and switch between them. It can also consolidate them if needed (for example, personal and business ledgers viewed together).
- Data Entry and Editing: Uniquely, Fava isn’t read-only – it has an editor and transaction entry form. You can add new transactions through a web form (it will insert the entry into your .beancount file). You can also open the source file in an external editor from Fava. Fava even supports “Gmail-style” keyboard shortcuts (press
?
in the UI to see them) for power users. This turns Fava into a lightweight accounting system where you can input and view data from the same interface. - Reports and Account Drilldown: Fava provides standard accounting reports: Income Statement (Profit & Loss), Balance Sheet, Trial Balance, and a holdings list for investments. The Balance Sheet and Income Statement are interactive – you can click an account to drill down into its details, or toggle between viewing at cost vs market value for assets. Fava also shows “unrealized gains” for investments if you have price data. It generates a journal view of all entries and allows filtering that journal by various criteria (great for finding specific transactions).
- Document Management: If you attach receipts or statements, Fava helps organize those. Beancount has a notion of a documents folder, and Fava lets you drag-and-drop files onto accounts or transactions – it will store them and add a document entry in your ledger. This is useful for keeping supporting documents linked with your ledger data.
- Customization via Extensions: Fava can be extended with plugins (written in Python) to add new reports or functionality. Some extensions are bundled (e.g. a portfolio list report for investments). We will discuss custom extensions later, but essentially Fava’s design allows injecting new pages, and even custom JavaScript, through its extension API. This means if a certain analysis or dashboard isn’t built-in, an advanced user can add it.
- Performance: Fava is efficient – it reloads the data in memory and serves pages quickly. The underlying Beancount parsing is quite fast (C++ optimized in the latest version), so even large ledgers load in a second or two. In practice, Fava can handle personal ledgers of many years, though extremely large files (tens of thousands of transactions) might benefit from some optimization (e.g. archiving old entries).
- Web Access and Mobility: By running Fava on a server or even your laptop, you can access your finances from any browser. Some users host Fava on a private server or Raspberry Pi so that they can check their finances on the go (possibly securing it behind a password or VPN since Fava doesn’t have built-in auth). This essentially gives you a self-hosted “web app” for your finances, without giving your data to a third party.
In summary, Beancount provides a robust foundation for transparent, text-based accounting with rigorous double-entry rules and multi-currency support. Fava builds on that by offering an accessible interface with immediate insights (reports, charts) and the ability to interact with your data. Together, they form a highly flexible accounting and analytics system that you control end-to-end.
Real-Time (or Near-Real-Time) Analytics with Beancount & Fava
Achieving real-time or near-real-time analytics with Beancount and Fava involves automating the flow of data into your ledger and ensuring the tools display up-to-date information. By default, Beancount is a batch process (you add entries to the file, then view reports), and Fava will detect changes and require a refresh. However, with the right setup, you can streamline updates so that new transactions and changes appear almost instantly.
File Change Detection: Fava monitors the ledger file for changes. If you edit the .beancount
file (or include files) in an editor, Fava will show a “Changes detected – click to reload” banner. Upon clicking (or pressing reload), it reloads the data and updates the view. In practice, this reload is very fast (usually under a second for typical ledgers). This means Fava can serve as a live dashboard if your ledger file is being updated frequently. (In debug mode, Fava can even auto-reload on file changes, though by default it waits for user confirmation to avoid disrupting your view.)
Continuous Import/Update Pipeline: To get real-time data, you need to automate the addition of transactions to the Beancount file. There are a few common strategies:
-
Scheduled Import Jobs (Cron): Many users set up a cron job (or scheduled task) to fetch new transactions from financial institutions periodically (say every night, or every hour) and append them to the ledger. For example, you might use the Beancount importer plugins to grab the latest bank transactions via API or OFX download. One Beancount user built an automation pipeline such that their books update themselves: “seeing my accounting book updating itself without me touching it in an open format brings me pure joy”. This was achieved by connecting to bank APIs and scheduling regular updates. Tools like
bean-fetch
(for OFX) or custom Python scripts using bank APIs (e.g. Plaid) can run on a schedule and write new entries to the ledger. After each scheduled import, if you have Fava running, you can simply refresh Fava to see the new data. -
File Watchers and Triggers: Instead of time-based schedules, you can use file watchers to react to events. For instance, if your bank can email you a daily statement or you drop a CSV in a folder, a script could detect that file (using
inotify
on Linux or similar) and immediately run the import routine, then signal Fava to reload. While Fava doesn’t yet support pushing a live reload to the browser, you would at least have the data updated so that next time you check the page or click reload, it’s current. Some community projects go further: for ledger (a cousin of Beancount), one user created a small server that exposes ledger data to Grafana in real-time, showing that a similar approach can be taken with Beancount – essentially build a daemon that feeds data to your dashboards continuously. -
Direct API Integration: Instead of going through files, advanced users might connect directly to bank APIs (like Plaid or regional Open Banking APIs) to pull transactions frequently. A motivated individual can script “live” imports in a loop (with appropriate rate limiting) – effectively polling the bank for new data every few minutes. There is nothing stopping you from “signing up with Plaid API and doing the same [automation] locally”. Each new transaction can be appended to the Beancount file as it arrives. With this approach, Fava truly becomes a real-time dashboard for your accounts, rivaling the up-to-date feed in commercial apps.
Data Refresh in Fava: Once your data is being updated, getting Fava to show it is straightforward: a browser refresh (F5) or clicking the reload banner will load the latest ledger state. If you prefer not to even click, running Fava with --debug
enables an autoreload for extension development which some have used to force immediate page reloads on changes. Alternatively, if you’re building a custom front-end, you could have it poll a small API that returns the latest balance or so from the ledger on a schedule.
Instant Calculations: Beancount’s fast parsing means even if you update your ledger file every few minutes, the turnaround from data fetch → file update → Fava reload is quick. For example, one user notes that reloading Fava after editing the file “is barely noticeable… definitely less than a second” for reasonably sized ledgers. Thus, you can keep a Fava window open and hit refresh periodically to mimic a live dashboard. (For a truly live experience, one could build a small script to auto-refresh the browser or use the browser’s refresh every N seconds feature.)
Reconciliation and Alerts: To trust real-time data, you also want to reconcile balances frequently. Beancount makes this easy with balance assertions and an “up-to-date” indicator. In fact, Fava offers colored indicators next to accounts if you mark them with a certain metadata (e.g. you can mark an account with fava-uptodate
metadata and Fava will color it red/yellow/green based on whether the last entry is a recent balance check). This can be used to quickly see if an account’s balance in the ledger matches the latest statement from the bank. In a near-real-time setup, you might automate daily balance checks (so each morning, the ledger has yesterday’s closing balance from the bank for each account). Fava’s indicator would then tell you if your auto-import missed something or if there’s a discrepancy, providing confidence that the “live” data you see is accurate.
Automation Example: Suppose you want daily cash flow updates. You could set a cron job to run at 3am every night: it executes a Python script that uses your bank’s API to fetch the last day’s transactions, writes them into import_today.beancount
, and then appends that file to your main ledger. It also writes a balance assertion for end-of-day. When you wake up, you open Fava – it shows all transactions through yesterday, and you see the current month’s income/expenses updated. If you make a spending during the day, you could manually add it (via Fava’s new transaction form on your phone, for example), or wait for the nightly import. This hybrid approach (mostly automated, with ability to manual add ad-hoc) gives a close-to-real-time picture. Another approach is to leave Fava’s Journal page open and use it as a register: as you spend, you quickly record the transaction (like entering in a checkbook) – then you are the real-time feed. This is more manual, but some users enjoy the awareness it brings. For truly streaming updates without manual steps, you’ll need to invest in scripting and possibly use third-party APIs as discussed.
In summary, by combining Beancount’s import automation with Fava’s rapid refresh, you can get near-real-time financial data. It may not be “push-button easy” to achieve the same level of live feed as a service like QuickBooks (which automatically pulls bank feeds), but it is possible – and importantly, you retain full control and transparency of the process. As one plaintext accounting advocate noted, a little effort up-front can yield an automated system that is “way better than commercial solutions, and far more flexible and extensible”. In the next section, we’ll see how Fava’s visualization capabilities let you immediately make sense of this up-to-date data, turning raw transactions into insights.
Visualization Capabilities in Fava (Cash Flows, Trends, Real-Time Inspection)
(GitHub - beancount/fava: Fava - web interface for Beancount) Fava’s Income Statement report (in the web UI) supports rich visualizations like treemaps (pictured) and sunburst charts for quick insight into the composition of income and expenses. In this treemap, each rectangle represents an expense category, sized by its amount – you can instantly see Rent (large green block) dominates expenses. The top filter bar and controls (upper right) allow changing the currency, chart type, and time period (e.g. viewing Monthly data). Fava also provides line charts (e.g. net worth over time) and bar charts (e.g. income vs. expenses by month) to help spot trends in your financial data.
One of Fava’s greatest strengths is turning the ledger data into visual, interactive reports instantly. As soon as the ledger is loaded, Fava generates charts that make it easy to understand cash flows and trends at a glance:
-
Income & Expenses Treemap/Sunburst: On the Income Statement page, Fava can display your income and expenses as either a treemap or sunburst diagram. These are great for “at-a-glance” cash flow visualization. For example, if your monthly expenses are shown as a treemap, the area of each rectangle corresponds to the magnitude of each expense category. Large blocks immediately show where most of your money went (e.g. rent or mortgage, taxes, etc.), while smaller blocks show minor expenses. This is extremely useful for spotting trends in spending – if the “Dining Out” block has been growing each month, you’ll notice it visually. You can toggle to a sunburst chart to see hierarchical breakdowns (e.g. the outer ring might show subcategories like Groceries vs Restaurants within the Food category). These charts update for whatever period you have filtered (one month, year-to-date, etc.), giving you instant cash flow visualization for that period. A user on the plaintext accounting forum noted: “I make a lot of use of the income and expense treemaps. They give a great visual sense of our fiscal movements.” – this kind of immediate understanding is exactly what Fava’s charts aim for.
-
Net Worth and Balance Over Time: Fava provides a line chart for net worth over time (on the “Balance Sheet” or “Statistics” page). This chart plots the sum of your assets minus liabilities at each point in time (by day, week, or month). It’s invaluable for trend spotting – you can see the trajectory of your finances (e.g. steadily upward, or dips at certain times). If you have investments, you can toggle between showing value at cost vs market (if price data is recorded) – for instance, you might see your net worth at market value fluctuates with stock prices, while at cost it’s smoother. Fava also can display account balances over time. If you click an account (say Assets:Bank:Checking), the account page shows a graph of that account’s balance history. You can instantly inspect how your cash account is moving – which is effectively a cash flow graph (the slope of the balance line indicates net cash flow). If it’s trending down, you know you’re spending more than earning in that period. By examining these trends, you might spot patterns like “every December my savings dip (holiday expenses)” or “my investments grew sharply this quarter”.
-
Bar Charts for Periodic Comparison: In the Income Statement view, Fava has tabs for “Monthly Profit”, “Monthly Income”, “Monthly Expenses” etc. Selecting these shows bar charts by month. For example, Monthly Net Profit will show each month’s surplus/deficit as a bar, making it easy to compare performance across months. You can quickly identify outliers (e.g. a big negative bar in April means that month had an unusual loss/expense). Similarly, “Monthly Expenses” bar chart stacks or groups expenses by category per month, so you can see which categories fluctuate. This is great for trend spotting across time – e.g. you might notice your “Travel” expenses spike every summer, or “Utilities” bills are higher in winter. Fava essentially gives you some of the capabilities of a budgeting app (tracking trends) but with full customizability (since you define the categories and how they roll up).
-
Real-Time Filtering and Data Inspection: The visualizations in Fava aren’t static; they work in tandem with Fava’s filtering. Suppose you want to inspect a specific scenario: “How do my quarterly cash flows look for my business accounts only?” You can set the time filter to Q1 2025 and filter accounts to your Business hierarchy – Fava will instantly update the charts to show net income, treemap of expenses, etc., but only for that subset. This interactive slicing means you can do ad-hoc analysis very quickly, without writing queries. The Journal view also supports live filtering: you can search by payee or narration substring and see a filtered list of transactions immediately. If you’re looking at real-time data (say you just imported last week’s transactions), you could filter by a tag like
#uncategorized
to see new transactions that might need categorization, or by@pending
(if you mark pending entries) to see what’s still not cleared. This real-time inspection capability helps ensure data quality as well—because you can isolate and address anomalies on the fly. -
Cash Flow Statement (indirect): While Beancount/Fava doesn’t produce a formal cash flow statement (Operating/Investing/Financing breakdown) out-of-the-box, you can mimic it with custom queries or by structuring accounts. For instance, you could tag certain transactions or use specific accounts for investing and financing, then query totals. Fava’s query interface lets you run a BQL query like:
SELECT sum(amount) WHERE account ~ "Assets:Bank" AND year = 2025
to get cash flow for the year, etc. That said, most personal users find the combination of balance trends and income/expense charts sufficient for understanding cash flows. -
Holdings and Portfolio Visualization: On the Holdings page, Fava lists your current holdings of commodities (e.g. stocks, bonds, crypto) with quantities, cost, market value, and unrealized gains. While this is a table, not a chart, it’s very useful for real-time inspection of your portfolio’s status. Some extensions (like fava-investor, discussed later) add more visuals for portfolios, such as allocation pie charts or performance graphs. Even without extensions, you can see e.g. how your stock portfolio value changes as of the latest prices – if you update price quotes regularly (which could be automated daily), Fava’s charts will reflect up-to-the-minute market value of your investments.
In practice, Fava’s visual reports update as quickly as the underlying data. The moment a new transaction is added and the page reloaded, the charts recompute. There’s no lengthy reprocessing needed. This means if you have a semi-automated pipeline feeding in data throughout the day, you can keep Fava open and periodically hit refresh to get updated charts – effectively real-time financial monitoring.
For example, imagine you’re running a small business and you want to monitor cash on hand and daily expenses. You could have Fava open to a custom dashboard (perhaps using an extension or the query screen) that shows “Cash account balance today” and “Expenses – Today vs. Yesterday”. Each time you refresh after new data comes in, you’d see those numbers update. This is akin to what expensive real-time dashboards provide, but using open-source tools. The difference is you might need to manually refresh or schedule refreshes, whereas those tools push updates automatically. But functionally, the insight you get is the same, with the added benefit that you can drill down into any number on Fava (click it to see underlying transactions) – something many BI dashboards lack.
In summary, Fava turns your accounting data into immediate visual insights: cash flow breakdowns, trend lines, comparisons over time, and interactive filtering all help you see the story behind the numbers. Whether you’re inspecting last week’s spending for anomalies or reviewing multi-year trends in net worth, Fava’s charts and reports provide clarity in real-time (as soon as your data is there). Next, we will see how you can extend these capabilities or integrate them with external tools if you need even more customized analytics.
Integration with External Dashboards and Visualization Tools
While Fava provides a rich set of built-in reports and charts, you might want to integrate Beancount’s data with other business intelligence (BI) or dashboard tools such as Grafana, Metabase, or custom web frontends (e.g. a React app). The motivation could be to combine financial data with other data sources, use advanced charting capabilities, or share dashboards with others in a different format. Thanks to Beancount’s openness, there are multiple ways to achieve integration:
-
Database Integration (BeanSQL / Beanpost): One straightforward approach is to export or sync your Beancount ledger to a SQL database. Once in SQL, any BI tool can query the data. In fact, community members have created tools for this. For example, Beanpost is an experiment that mirrors a Beancount ledger into a PostgreSQL database, implementing much of Beancount’s logic as SQL functions. This provides “a flexible backend that can integrate with other tools like web apps or reporting systems.” You can run Beanpost to continuously sync your text ledger to Postgres. Then, a tool like Metabase or Tableau can connect to that Postgres database and you can build any charts or dashboards you like (live updating as the DB updates). One user reported using Postgres + PostGraphile to automatically expose a GraphQL API for the ledger data and then writing a custom React front-end on top of that – essentially treating the ledger as a web service. This approach addresses cases where Fava’s interface might not be sufficient (e.g. multi-user access, or more mobile-friendly UIs). It’s more engineering-heavy, but it shows the potential: you can integrate Beancount with modern web stacks relatively easily. A lighter-weight variant is using Beancount’s built-in SQLite support – running a query like
bean-query -e ledger.beancount "SELECT ..."
can output results, or using Beancount’s Python API to get data and insert into a SQLite DB. Some people use SQLite as an intermediate to plug into tools like Metabase (which can read SQLite files via a connection). -
Grafana (Time-Series Dashboards): Grafana is popular for monitoring and time-series data. Financial data over time (expenses, balances) can be treated as time-series. There has been community discussion on connecting Beancount to Grafana. One idea was a Grafana Data Source Plugin that could run BQL queries against a Beancount file on the fly. This would allow Grafana panels to directly display, say, “Balance of Checking account” as a gauge or “Expenses over last 30 days” as a graph, by querying the ledger. As of now (2025), a dedicated plugin isn’t published, but enthusiasts have built ad-hoc solutions. For instance, a Reddit user aquilax built a simple server that makes Ledger CLI data available to Grafana, and shared it as grafana-ledger-datasource-server. A similar concept can be applied to Beancount: you’d write a small HTTP server in Python that loads the Beancount ledger (using Beancount’s API to query data) and exposes endpoints that return JSON data frames for Grafana. Grafana has a generic JSON data source plugin which could then pull from this API. In practice, this means you could design a Grafana dashboard with panels like “Monthly Revenue (bar chart)” or “Daily Cash Balance (line chart)”, and those panels fetch data from your Beancount-driven API. Grafana would allow rich visualization options (annotations, thresholds, combine with server metrics, etc.). Andreas Gerstmayr (one of Fava’s maintainers) suggested exactly this approach and even mentioned he created a Fava extension called fava-dashboards (more on that below) to render charts from BQL queries, as an alternative to a full Grafana setup. If you prefer Grafana’s UI, integration is feasible – it just requires building the data bridge.
-
Metabase (Ad-hoc Queries and Dashboards): Metabase is a user-friendly BI tool that lets you run queries and make dashboards without code. If you export your ledger to a relational format (via Beanpost or by writing out tables of transactions, postings, etc.), you can point Metabase at that database. You might create custom tables like
expenses (date, category, amount)
from your ledger, and then in Metabase you can generate charts easily (e.g. a pie chart of expenses by category for last month). The benefit is non-technical users (or colleagues) could then interact with the data through Metabase’s GUI without needing to touch the Beancount file. The downside is you need to maintain the export/sync. Some users have automated nightly conversion of the Beancount ledger to SQLite, then let Metabase read the SQLite; others might use the Postgres approach mentioned. The key is that data portability of Beancount enables this – you’re free to duplicate the data into any form your external tool needs. -
Custom Frontends / Applications: If you have specific needs, you can always write a custom application on top of Beancount. The Beancount Python library gives you access to all parsed entries, balances, etc., so a Python web framework (Flask, Django, FastAPI) can be used to build a tailored app. For example, a small business might build a dashboard that shows KPI metrics (like gross margin, daily sales, etc.) by querying the ledger and perhaps combining with non-ledger data (like number of customers served). One community member built a mobile-friendly web UI because Fava wasn’t intuitive for their spouse – they leveraged the ledger in a database to drive this custom UI. If you prefer JavaScript/TypeScript, you could use a tool to convert the ledger into JSON and build from there. Some projects like beancount-web or beancount-query-server have been floated in the community to expose Beancount data over an API, although Fava’s API (if running in “headless” mode) could also be used – Fava does have an API endpoint for queries internally.
-
Excel/PowerBI Integration: It’s worth noting you can even integrate with Excel or PowerBI. Beancount (and Fava via an add-on) can export query results to CSV or Excel files. A workflow could be: a nightly job generates an Excel file of key financials from Beancount, and PowerBI is set to import that file. This is a bit indirect, but for organizations that already use Excel/PowerBI heavily, it’s a low-friction integration. PowerBI also supports Python data sources, so one could write a short Python script that runs BQL queries and use it as a data source within PowerBI, achieving a direct connection.
Case Study – Grafana Integration Idea: Josh, a Beancount user, asked on the mailing list about pushing Beancount metrics to Prometheus and viewing in Grafana. The core devs responded that instead of duplicating data in Prometheus, a better approach is a Grafana plugin or service that directly queries the Beancount ledger. Andreas shared his fava-dashboards
extension which renders custom charts within Fava itself as an example solution. The takeaway is: you have options – either integrate via existing BI infrastructure (Prometheus+Grafana or SQL+Metabase) or extend Fava to meet your needs (the next section will dive into that).
Security and Multi-User Considerations: If integrating into external tools, be mindful of data sensitivity. Beancount’s plain text often contains private financial info, so any server exposing it should be secured (authenticated). If you move data to a cloud BI tool, you might lose some privacy. Self-hosted tools (Grafana/Metabase open-source versions) can be run locally to mitigate that. Also, if multiple people need to view dashboards, an external read-only dashboard might be preferable to giving everyone access to Fava (where they could edit data if not careful). For example, a startup could use Beancount internally but use Metabase to let department heads see spend vs budget without touching the ledger files.
In summary, Beancount and Fava play well with others. You can leverage the entire ecosystem of data tools with a bit of glue code: push ledger data to a SQL database for BI tools, serve it via APIs for web apps, or even use specialized libraries to stream it to time-series systems. This flexibility means you’re never stuck if Fava’s built-in visuals don’t fulfill a niche requirement – you can always integrate into another platform while continuing to use Beancount as your source of truth. Next, we’ll look at extending Fava itself with plugins and custom dashboards, which is often an easier route than external integration if you just need a few extra features.
Custom Dashboards and Extending Fava with Plugins (Code Examples)
Fava is designed to be extensible: you can add new pages, charts, and behaviors by writing Fava plugins (extensions) in Python. This allows tailoring the web interface to your specific needs without building an entire separate app. We’ll explore two key avenues for customization: (1) Using or writing Fava Extensions, and (2) Setting up custom dashboards via community plugins like fava-dashboards.
Fava Extensions (Custom Plugins)
A Fava extension is essentially a Python module that defines a subclass of FavaExtensionBase
. When Fava starts, it can load this module and integrate it into the app. Extensions can register new report pages, hook into events, and even include custom JavaScript for interactivity. Some extensions come bundled with Fava (e.g. portfolio_list
for an investment overview page). Others can be installed via pip or written from scratch.
To enable an extension, you use the Beancount custom directive in your ledger file:
2010-01-01 custom "fava-extension" "my_extension_module" "{'option': 'value'}"
This tells Fava to load the given module. For example, the built-in Portfolio List extension is enabled internally similarly. If you installed an extension via pip, you’d reference its module name here. The optional JSON at the end is configuration for the extension (passed to it as a string).
Example – Auto-Commit Extension: Fava has an example extension fava.ext.auto_commit
(bundled) which automatically commits changes to a VCS when you edit the file via Fava’s editor. If you wanted to use it, you’d add:
2025-01-01 custom "fava-extension" "fava.ext.auto_commit" "{'repo': '/path/to/git/repo'}"
This extension registers a hook that runs after each file edit to perform a git commit
. It demonstrates how extensions can hook into Fava’s events (here, after saving the file).
Example – Portfolio List Extension: This extension adds a page that shows your investments grouped by asset class, etc. It has a report_title = "Portfolio List"
and includes a template to render the data. Fava detects that and adds a new sidebar entry “Portfolio List” under Reports. The extension also includes a bit of JavaScript (with has_js_module = True
) to enhance the page (perhaps for interactive charts on that page). To enable it (if it weren’t already default), you’d do:
2025-01-01 custom "fava-extension" "fava.ext.portfolio_list"
(No config needed in this case.)
Writing a Custom Extension: Suppose you want a custom report page, say “Receivables Aging” for invoices. You could create a file receivables.py
like:
# receivables.py
from fava.ext import FavaExtensionBase
class ReceivablesReport(FavaExtensionBase):
report_title = "Receivables Aging"
def on_page_load(self):
# This could be a hook to gather data
pass
You’d also create a templates/ReceivablesReport.html
to define the HTML for the page. In that template, you can access self.ledger
(the Beancount ledger object) and compute things. For example, loop through transactions to find those tagged as invoices and not yet paid, and group by age. Once this extension is written, you add to your ledger:
2025-01-01 custom "fava-extension" "receivables"
(assuming receivables.py
is in the Beancount file directory or PYTHONPATH, Fava can find it by name). On starting Fava, you’d now see a “Receivables Aging” page.
Under the hood, Fava will call your extension’s methods at appropriate times. You can override methods like after_load_file
(to do calculations after ledger loads) or use hooks like before_request
. The extension can also define routes or API endpoints if needed, but typically using the provided hooks and a template is enough.
The Fava docs note the extension system is still evolving, but it’s usable. In fact, many advanced features have been prototyped as extensions.
Custom Dashboards with fava-dashboards (Community Extension)
Instead of writing an extension from scratch, you might use the fava-dashboards plugin created by a Fava maintainer. This extension allows you to define arbitrary dashboards via a YAML (or JSON) config file, mixing text, tables, and charts, powered by BQL queries. It’s basically a way to create new “pages” in Fava that contain multiple custom panels.
Installation and Setup: First, you install the package (e.g. pip install fava-dashboards
). Then in your Beancount file, activate it with a custom directive pointing to your dashboards config. For example:
2010-01-01 custom "fava-extension" "fava_dashboards" "{ 'config': '/path/to/dashboards.yaml' }"
(fava-dashboards/README.md at main · andreasgerstmayr/fava-dashboards · GitHub). This tells Fava to load the extension and use your YAML file for configuration.
Dashboards YAML format: In the dashboards.yaml
, you define one or more dashboards and their panels. For instance:
dashboards:
- title: "Cash Flow Dashboard"
panels:
- title: "Net Cash This Month"
width: 50%
queries:
- bql: "SELECT sum(position) WHERE account ~ 'Income' OR account ~ 'Expenses'"
type: "jinja2"
template: "<h1>{{ panel.queries[0].result | float }} USD</h1>"
- title: "Cash Balance Trend"
width: 50%
queries:
- bql: "SELECT date, balance WHERE account = 'Assets:Bank:Checking'"
type: "echarts"
script: |
const dates = {{ panel.queries[0].result | safe }}.map(row => row[0]);
const balances = {{ panel.queries[0].result | safe }}.map(row => row[1]);
return {
xAxis: { type: 'category', data: dates },
yAxis: { type: 'value' },
series: [{ data: balances, type: 'line' }]
};
This is a hypothetical example to illustrate. The first panel calculates net cash (income minus expenses) for the current filter and displays it as a big number (using a Jinja2 template). The second panel runs a query to get the daily balance of checking account and then uses an ECharts script (ECharts is a JS chart library) to plot a line chart. Fava-dashboards supports panel types: html, jinja2, echarts, d3_sankey, etc., and provides data to the scripts. Essentially, it gives you full flexibility to design dashboards with multiple components – without writing a full Fava extension from scratch.
The extension takes care of rendering these when you open the dashboard page in Fava. You can create multiple dashboards (each appears as a tab or separate page). This is extremely powerful for creating custom financial dashboards. For example, you could make a “Budget vs Actual” dashboard: one panel shows a table of budget vs actual per category (via a query comparing two accounts sets), another panel shows a bar chart of year-to-date spending vs prior year, etc. All of this with just configuration and minimal scripting, leveraging your ledger data via BQL.
Code Example – Enabling fava-dashboards: As shown above, adding the extension is one line in your ledger. For completeness, here’s a minimal example of that in context:
option "title" "My Ledger"
option "operating_currency" "USD"
plugin "beancount.plugins.auto_accounts" ; (auto-opens accounts)
1970-01-01 custom "fava-extension" "fava_dashboards" "{ 'config': 'dashboards.yaml' }"
And in dashboards.yaml
:
dashboards:
- title: "Overview"
panels:
- title: "Net Worth"
queries:
- bql: "select sum(position) where account ~ 'Assets|Liabilities'"
type: "jinja2"
template: "<div>Net Worth: {{ panel.queries[0].result[0,0] }}</div>"
(This would display net worth in a simple div; a real example would format nicely and add more panels.)
With this in place, when you run Fava and navigate to the “Overview” dashboard, it will show your computed net worth. You can then refine the template or add charts as needed.
Other Notable Extensions: Aside from fava-dashboards, there are plugins like fava-investor which provides advanced investment analysis (asset allocation charts, tax-loss harvesting tools, etc.). Enabling fava-investor (after pip install fava-investor
) adds multiple report pages related to investments. Another one is fava-review (for transaction review over time), etc. The community maintains an “awesome-beancount” list which includes various plugins and tools. By browsing these, you might find a pre-built extension that meets your needs.
When to extend vs integrate externally: Generally, if your need is purely presentation or calculation on the existing ledger data, a Fava extension is ideal (keeps everything in one place, respects filters, etc.). If your need involves combining external data or you require a drastically different UI, external integration (previous section) might be warranted. For example, showing website analytics alongside finances – better in Grafana/Metabase; but adding a new financial KPI or report – better as a Fava plugin.
Example – A Custom KPI in Fava: Let’s say you want to track “Savings Rate” (percentage of income saved). You could do this with an extension that calculates it and shows a little box on the main page. Or with fava-dashboards, one panel could be a Jinja2 that outputs Savings Rate: X%
by querying total income and total expenses. This kind of custom metric is very easy to inject with these tools, whereas in a closed system like QuickBooks it might be impossible to create a new metric on the dashboard.
To illustrate how concise it can be, here is a pseudo-code using fava-dashboards in YAML:
- title: "Savings Rate"
panels:
- title: "Savings Rate"
queries:
- bql: "SELECT sum(position) WHERE account ~ 'Income'"
- bql: "SELECT sum(position) WHERE account ~ 'Expenses'"
type: "jinja2"
template: |
{% set income = panel.queries[0].result[0][0] %}
{% set expense = -panel.queries[1].result[0][0] %} {# expenses are negative in income statement #}
{% set rate = (income - expense) / income * 100 if income != 0 else 0 %}
<h3>Savings Rate: {{ rate|round(1) }}%</h3>
This would calculate the savings rate (assuming Income accounts sums come out positive, Expenses as negative in BQL query context) and display it.
The key point: Fava is not a static tool – it’s an extensible platform. With a bit of Python or even just config code, you can tailor it extensively. Many users share small scripts or extensions on forums to do things like show upcoming bills, generate PDF invoices from transactions, or integrate Beancount with tax calculation libraries. When you invest in learning or using these extensions, you get a very bespoke financial analytics system without starting from scratch.