Most banking platforms today are built around a familiar model. Databases store what accounts, loans, and balances look like at this moment, and applications update those records as things change. This is often referred to as an update-in-place persistence model. Historical information exists, but it typically sits beside the system rather than defining it.
Over time, this model runs into fundamental limitations. Banks need full auditability, precise historical reconstruction, safe retries, and the ability to evolve products without risking existing data.
The usual response is to layer additional systems on top: audit logs, reconciliation jobs, retry guards, historical tables, migration frameworks. Each new capability becomes another system that must stay in sync.
With Lana, our banking and lending platform, we took a different approach. Instead of layering these guarantees on later, we designed the architecture so they are natural consequences of how the system works.
Traditional Approach
- Mutable database rows overwritten on each change
- Separate audit log that can drift from reality
- Database migrations to evolve products
- Custom retry guards to prevent duplicates
- Historical reconstruction requires extra systems
Event-Sourced (Lana)
- Immutable events are the source of truth
- Audit trail is the operational data
- New event types extend products additively
- Idempotency is built into the model
- Replay events to reconstruct any point in time
Every Entity Is Event Sourced
In our banking platform, Lana, every domain entity is reconstructed from a sequence of immutable events.
The platform spans domains such as credit, deposits, customers, accounting, custody, access control, governance, and collections, all built on the same event-sourced foundation.
A credit facility, for example, is not stored as a mutable record. Its lifecycle is represented as events such as facility initialized, activated, collateral added, interest accrued, disbursement issued, and matured.
Instead of storing only the latest state, the system stores how it came to exist. That single difference unlocks capabilities that are difficult to implement reliably in traditional architectures, while still supporting efficient querying and access patterns.
Auditability
Auditability Is Built Into the Data Model
In regulated financial systems, auditability is mandatory.
Institutions must be able to explain how balances changed, why credit decisions were made, and when transactions occurred. In most systems this is handled by a separate audit log that attempts to record what the main system did.
In practice, these logs drift from reality.
In Lana, our banking platform, the audit trail is the system itself.
Every state change is an event stored permanently with metadata such as timestamps, transaction identifiers, and contextual information. Because entities are reconstructed directly from those events, the audit record cannot diverge from the operational data.
There is no difference between the data used to run the system and the data used for compliance.
InvestigationsTime Travel When It Matters
A common question in banking investigations sounds simple but can be difficult to answer precisely:
"What was the exact state of the system at the moment this transaction happened?"
Consider a fraud investigation.
A customer reports that a large transfer from their account was unauthorized. The transaction happened months ago and has now been escalated to law enforcement. Investigators need to understand exactly what conditions existed when the payment was processed.
Questions quickly extend beyond the transaction itself:
- Was the transaction within the account's configured limits at the time?
- Did the account have additional signatories or permissions?
- Were any fraud risk flags already active?
- What was the state of the customer's identity verification and risk profile at that time?
With event sourcing, the system can reconstruct the account exactly as it existed at that moment by replaying events up to that point in time.
This allows investigators to answer those questions with precision, based on the system's actual history rather than logs or approximations.
For fraud investigations, this level of accuracy reduces resolution time and improves outcomes for customers.
ReliabilityIdempotency and Operational Safety
Retries are inevitable in distributed systems. What matters is whether they are safe.
In financial systems, a single incorrect retry can lead to duplicate transactions or inconsistent balances.
In Lana, our banking platform, commands are designed to be idempotent. Each operation determines from the event history whether it has already been applied and returns a result indicating whether it executed or was already handled.
This ensures that retries do not introduce inconsistencies, even under failure conditions.
Evolution
Safer Evolution of Financial Products
Financial products evolve constantly. Regulations change, new features are introduced, and business models adapt.
In traditional systems, evolving an entity often requires database migrations and transformations of existing data.
With event sourcing, new capabilities are introduced by defining new event types. Existing entities simply do not contain those events.
For example, adding support for early loan repayment introduces new events. Loans created before that feature existed continue to behave exactly as before.
There is no need to backfill or modify historical data. The system evolves without putting existing data at risk.
The same event history also enables new projections such as reporting, analytics, and risk views without changing core entities.
Developer ExperienceMaking Event Sourcing Practical
The Real Cost of Event Sourcing
Event sourcing is powerful, but it is rarely adopted as a system-wide standard. Part of the reason is that it is less familiar than traditional approaches. More importantly, it is perceived as complex and costly to implement and maintain at scale.
A production-grade event-sourced system requires far more than storing events. Each entity needs infrastructure for event persistence, state reconstruction, concurrency control, querying, pagination, error handling, and transactional guarantees. Without strong abstractions, this leads to large amounts of repetitive and error-prone boilerplate.
This is where most implementations stop. Teams adopt event sourcing selectively for a few complex domains, while the rest of the system falls back to traditional patterns.
es-entity: A Reusable Foundation
To make event sourcing viable across the entire platform, we built es-entity, an open-source event sourcing library written in Rust.
The library moves this complexity out of application code and into a reusable foundation. Developers define the domain: the entity, its events, and the business logic. The rest is generated automatically at compile time.
From a minimal definition, the library provides:
Typed Repositories
Standard access and query methods, strongly typed at compile time.
Generated SQL
Common queries generated and verified at compile time. No hand-written SQL.
Concurrency Control
Optimistic locking based on event sequence numbers prevents conflicts.
Transactions
Multi-entity workflows with transactional guarantees across aggregates.
Idempotency
Built-in primitives that check event history before applying operations.
Error Handling
Structured errors with database constraint mapping for clear failure modes.
Querying Without Compromise
A common concern with event sourcing is how to query data efficiently.
To solve this, our platform Lana (through our event sourcing library, es-entity) maintains a query-optimized index per entity alongside the event stream. This index contains only the fields needed for lookups, filtering, and constraints, and is updated atomically with each event write.
This allows the platform to support efficient queries such as finding customers by email, listing facilities by status, or enforcing uniqueness constraints, without scanning event streams or compromising the event-sourced model.
Developer Experience in Practice
In practice, developers do not write infrastructure code. They define events, implement state transitions, and express business rules. Idempotency, concurrency, and transactional consistency are handled as part of the underlying model rather than as ad hoc concerns.
This changes the economics of event sourcing.
Instead of requiring specialists and significant upfront investment per entity, the pattern becomes repeatable and consistent across the entire system. The complexity is still there, but it is isolated and solved once.
Without this level of automation, applying event sourcing consistently across a banking system is impractical.
TradeoffsThe Tradeoffs
Event sourcing introduces upfront complexity. Developers must think in terms of event flows, and systems must handle eventual consistency in projections.
Another challenge is event evolution over time. Because events are immutable, changing or deprecating existing event types requires careful handling. Systems must maintain compatibility with historical events, and developers need to design for versioning and long-term schema stability.
However, financial platforms still need auditability, idempotency, historical reconstruction, and safe evolution. In traditional architectures these are implemented as separate systems and maintained over time.
Event sourcing provides these guarantees structurally.
The complexity appears earlier, but the system remains easier to extend and reason about as it grows.
ConclusionA Platform Designed for the Long Term
By making history the source of truth, our banking platform Lana gains guarantees that are difficult to retrofit onto traditional architectures. For financial institutions building modern banking infrastructure, particularly those integrating Bitcoin and programmable financial systems, these properties are essential.
Full auditability: the audit trail is the operational data, not a separate system that can drift.
Historical reconstruction: replay events to any point in time for investigations, compliance, or debugging.
Safe retries: idempotent commands prevent duplicate transactions, even under failure conditions.
Additive evolution: new event types extend products without migrations or risking existing data.
As systems grow more complex, maintaining these properties as separate concerns becomes increasingly difficult. Event sourcing makes them part of the foundation. That is why, in our platform Lana, it is the standard across the entire system.