Beancount.Renderer turns a stream of directive structs into valid Beancount
text. Rendering is pure and deterministic: rendering the same stream twice
produces byte-identical output. This is the foundation of golden-file testing
and of using Beancount as an oracle.
The directive protocol
Every directive struct implements the Beancount.Directive protocol, which
defines a single function:
@spec to_bean(t()) :: iodata()Beancount.Renderer.render/1 calls to_bean/1 on each directive and joins the
fragments with a blank line, terminating the document with a single newline.
iex> Beancount.render([Beancount.open(~D[2026-01-01], "Assets:Bank", ["USD"])])
"2026-01-01 open Assets:Bank USD\n"What is supported
- dates - rendered as ISO-8601
YYYY-MM-DD. - flags - transaction flags (
*,!) and per-posting flags. - postings - amounts right-aligned for readability.
- metadata -
key: valuelines, emitted in sorted order for determinism. - tags & links -
#tagand^linksuffixes, sorted. - commodities - currency codes on postings, balances and prices.
- quoted strings - payees, narrations, notes, documents, events, and
string metadata, with
"and\escaped. - cost & price annotations -
{10.00 USD}cost basis and@/@@prices.
Posting alignment
Within a transaction, amounts are right-aligned so decimal values line up:
2026-01-31 * "Employer" "Salary"
Assets:Bank 5000 USD
Income:Salary -5000 USDAlignment is computed per transaction and is fully deterministic.
Determinism guarantees
- Metadata keys are sorted.
- Tags and links are sorted.
- Decimals are rendered in plain (non-scientific) notation.
These rules mean output never depends on map ordering or runtime state, so it is safe to commit rendered output as golden fixtures.