Zitadel vs ClavionX: Event Sourcing vs Event-Carried State
Both platforms are event-driven; they disagree about what an event is. Event sourcing vs event-carried state, Actions v2 moving code out of process, project grants, and AGPL.
Two identity platforms describe themselves as event-driven. Both have an event pipeline, both have projections, and both accept that some reads are eventually consistent. An architect skimming the two sets of docs could reasonably conclude they made the same foundational decision.
They didn't. Zitadel is event-sourced: the events are the data, and everything else is derived from them. ClavionX uses event-carried state transfer: the data lives in ordinary relational tables, and events carry copies of it to the systems that need to read it. The words overlap and the consequences diverge. They differ in what you can reconstruct, what you can change, what breaks during an upgrade, and where your audit trail comes from.
That distinction is the most useful thing to take from this comparison, and it applies well beyond these two products.
Disclosure: I work on ClavionX. Zitadel is a thoughtfully engineered open-source platform, and for several kinds of team it's the better choice. The post says which.
What Zitadel actually is
Zitadel is an identity platform written in Go by a Swiss company, available self-hosted or as Zitadel Cloud. Its model is built around B2B from the start. An instance contains organizations. Organizations own users and projects. Projects contain applications and roles. A project grant lets one organization offer its project, with a chosen subset of roles, to other organizations. It supports OIDC, OAuth 2.0 and SAML, passkeys, MFA, identity brokering, a hosted login, and RFC 8693 token exchange, including impersonation and delegation, since v2.49.
Two recent decisions matter to evaluators. With v3 in 2025, Zitadel moved from the Apache 2.0 license to the AGPL 3.0, and it standardized on PostgreSQL, dropping CockroachDB. Both were explained openly as sustainability and focus decisions, and both are worth understanding before adoption. The license note is further down.
Event sourcing: the events are the database
In Zitadel, every change is written as an immutable event to an event store: user added, email changed, organization renamed, project granted. The event store is the single source of truth. The tables you query are projections, built by handlers that consume events and write read-optimized views. This is CQRS: commands append events, and queries read projections.
flowchart LR
subgraph Z["Zitadel — event sourcing"]
direction LR
ZC["Command"] --> ZE[("Event store<br/>source of truth")]
ZE --> ZP["Projection handlers"] --> ZV[("Read views")]
ZQ["Query / login"] --> ZV
end
subgraph C["ClavionX — event-carried state"]
direction LR
CC["Admin change"] --> CT[("Relational tables<br/>source of truth")]
CT -- "same transaction" --> CO[("Outbox")]
CO --> CP["Event processor"] --> CR[("Runtime projection")]
CL["Login"] --> CR
end
What this buys is real:
- History is intrinsic. "What did this user's record look like last March, and who changed it?" is answerable, because the history is the data. An audit trail doesn't need to be engineered separately.
- New read models are cheap. Need a new query shape? Write a projection and replay the events into it.
- Nothing is overwritten. Mistakes are visible, and state can be reconstructed as of any point.
What it costs is less obvious and, for an identity system, important:
- Events are forever, so their schemas are forever. Every version of every event type ever written has to stay readable, because rebuilding state means replaying all of them. That makes the event schema a permanent public API, whose most demanding consumer is your own future code.
- Projections have to be rebuilt. Adding or changing a projection, sometimes as part of an upgrade, means replaying history into it. On a large, long-lived instance that's real work with real duration. Operators need to know which upgrades trigger it and how long it takes on their data.
- Read-your-writes needs care. A command succeeds when the event is stored. A query immediately afterwards reads a projection that may not have caught up yet.
None of these are defects. They're the known price of event sourcing, and Zitadel has engineered around them for years. They're still costs an operator inherits, and it's worth asking about them specifically when evaluating any event-sourced system.
Event-carried state: the events are copies
ClavionX made a different choice. The control plane's source of truth is a relational schema. Clients, tenants, users and policies are rows, updated in place. When a change commits, a transactional outbox in the same database transaction records an event. For configuration, that event carries the full current state of the changed entity, not a delta. An event processor consumes those events and materializes the projections that the separate login-serving runtime reads. The runtime never queries the control plane during a request.
The trade-offs mirror Zitadel's:
- Events can evolve freely. They aren't the source of truth, so no one ever needs to replay a two-year-old event to reconstruct anything. Changing an event's shape is an ordinary versioned-contract change, not a permanent obligation.
- Projections heal themselves. Every configuration event carries full state, so a missed or duplicated event is repaired by the next one, and any projection can be rebuilt from current tables rather than from all of history. If the projection a login needs is missing, the runtime fails closed rather than guessing.
- History isn't intrinsic. Overwriting rows means the past is gone unless something recorded it. ClavionX keeps a separate, append-only audit trail for that. That's a second system to design and trust, and the argument for keeping it separate is made in Identity Isn't Your Audit System and Immutable Audit Logs Are an Engineering Feature.
The general lesson holds regardless of vendor. Events as source of truth and events as a replication mechanism are different architectures that share a vocabulary. The first makes history free and schema evolution expensive. The second makes schema evolution cheap and history a separate job. When a vendor says "event-driven", ask which one they mean. The answer predicts what your upgrades and your audit story look like. Why Every Identity Team Eventually Builds an Event Bus explains why almost everyone ends up with some event pipeline. What the events are for is the real decision.
Actions: moving code out of process
Zitadel's extensibility history is the third vendor migration of this kind in this series, and the most instructive.
Actions v1 ran customer JavaScript inside Zitadel, in an embedded JavaScript runtime, at points in the login and token flows. Actions v2 replaced that with targets: external HTTP endpoints that Zitadel calls, either as webhooks or as calls whose response modifies the request or response in flight, before or after API operations and functions. Actions v2 became the complete replacement in v4. Actions v1 is deprecated, and Zitadel has published plans to remove it. Zitadel explained the move in its own writing as leaving the sandbox for an external, cloud-native model.
Set that beside Auth0, which replaced Rules with Actions, a better sandbox but still hosted code, and it forms a pattern. Vendors that let customers run code in-process keep migrating away from it. Each migration costs customers a rewrite. That's the strongest empirical support for the argument in The Extensibility Trap: in-process customer code is hard enough to live with that the vendors who offered it are paying to stop.
Moving code out of process solves the isolation problem. It doesn't solve the dependency problem. An Actions v2 target has a configurable timeout, up to several minutes, and an interrupt on error flag. With the flag off, a failing target is skipped and the operation continues, which is fail-open. With it on, a failing target aborts the operation, which is fail-closed. Zitadel's documentation includes a blunt warning. With interrupt on error enabled, a broken target can make the instance unusable, because every affected API call errors, including the ones you'd need to fix the configuration.
That warning is the fail-open versus fail-closed dilemma, turned into a checkbox, with the vendor honestly pointing out that one setting can lock you out. Both settings are sometimes right. The decision now belongs to whoever configures each target, which means it has to be reviewed like code even though it's configuration.
ClavionX has no equivalent. There are no targets, no hooks and no synchronous calls to customer systems, apart from LDAP password verification for tenants that use a directory. Its alternatives are declarative claim mapping and data pushed ahead of time through SCIM. The trade is the same one made against every vendor in this series: no lockout risk from a customer endpoint, and no way to express logic a target could.
Tenancy: two close relatives
Zitadel's project grants and ClavionX's global applications solve the same B2B problem in recognizably similar ways. In both, one application definition can serve many customer organizations without being copied into each one.
The differences are in scope and in what each tenant controls. In Zitadel, the granting organization chooses which roles each other organization receives, and the receiving organization manages its own users' authorizations within that set. Organizations are the tenant boundary within an instance. Separating issuers and signing keys means separate instances, which Zitadel supports. In ClavionX, each tenant has its own OIDC issuer and signing keys by default. A global application's security posture covers redirect URIs, grant types, PKCE and token policy, and a tenant can't loosen it.
For most B2B products Zitadel's model is more than adequate, and its role delegation between organizations is richer than ClavionX's today. ClavionX's model matters when customers require cryptographic separation, meaning their own issuer and their own keys, without the operational weight of a separate instance each.
The license question
AGPL 3.0 requires that if you modify Zitadel and offer it to users over a network, you make your modifications available under the same license. Running an unmodified Zitadel as your product's identity service is a common reading of acceptable use. Many organizations nonetheless have policies that restrict AGPL software regardless, and some embedding or redistribution scenarios need real legal review. Zitadel publishes a licensing FAQ and offers commercial terms. Treat the license as an explicit evaluation item, not a footnote, because a mid-project legal objection costs more than a technical one.
When Zitadel is the better choice
Pick Zitadel when:
- You want open source, with an actively developed codebase you can read, run and contribute to, and AGPL is acceptable to your organization.
- B2B role delegation matters, meaning organizations granting projects and roles to other organizations, which is a first-class model.
- You need token exchange or impersonation today.
- Intrinsic history appeals to you, and your team is comfortable operating an event-sourced system, including projection rebuilds.
- You need to extend flows and can accept out-of-process targets with deliberately configured failure behavior.
ClavionX fits better when you want per-tenant issuers and keys without running an instance per customer, and when the login-serving runtime must be a separate service that never waits on the control plane. It also fits when you'd rather have no customer-configured synchronous calls in the auth path at all, and when you prefer event schemas that can change freely over history that comes for free. Weigh that against ClavionX's youth and its planned-but-unbuilt token exchange and agent identity model.
The actual difference
Zitadel and ClavionX both concluded that an identity platform should be built around events, and then disagreed about what an event is. For Zitadel, an event is a fact that's permanently true, and the system is the sum of its facts. For ClavionX, an event is a message saying "here's the current state", and the system is its tables.
Both are coherent, and both come with an operational bill. The first charges it at upgrade time and in schema discipline. The second charges it in a separately built audit trail. Knowing which bill you'd rather pay is most of the decision, and asking every "event-driven" vendor which one they mean is the fastest way to find out what you're actually buying.
Vendor details are from Zitadel's public documentation, announcements and repository as of September 2026. ClavionX architecture details are from its published ADRs and docs; capability status from its feature matrix. I work on ClavionX.