Most Keycloak comparisons turn on price and lock-in. Against Zitadel neither argument works: both are open source, both self-host, both speak OIDC, OAuth 2.0 and SAML. What actually separates them is the licence you inherit, how you federate users that already exist, and whether your custom login logic runs inside the server or on an endpoint you have to host. Checked against Keycloak 26.8.1 and Zitadel v4.20.0 on 2 November 2026.
| Zitadel | You Keycloak | |
|---|---|---|
| Open source and self-hostable | ||
| Permissive licence (Apache 2.0) | ||
| LDAP / AD federation with sync | ||
| Extend it without writing Java | ||
| Runs as one service plus a database | ||
| Idle memory, quickstart as published | ~249 MB | ~611 MB |
| Dimension | Zitadel | Keycloak (with Phase Two) |
|---|---|---|
| Licence | AGPL-3.0-only, with proto/ and the docs under Apache 2.0 and the login app and client SDKs under MIT; a commercial licence is sold alongside | ✓Apache 2.0 throughout |
| Project governance | Single-vendor project; contributions accepted only under Apache 2.0 while the distribution is AGPL | ✓CNCF Incubating project, accepted 10 April 2023 |
| Implementation | Go, event-sourced on PostgreSQL 14-18 | Java on Quarkus; postgres, mysql, mariadb, oracle, mssql or tidb |
| Deployment shape | Published quickstart runs four containers: proxy, Go API, Next.js login app, PostgreSQL | ✓One server process and one database |
| Login UI customization | Console branding — logo, colours, font, watermark toggle. Past that you fork the MIT login app and run it yourself | ✓Themes override any login, account or email template, deployed into the server |
| Existing LDAP or Active Directory | LDAP configured as an identity provider: bind at login, attributes mapped at login | ✓User storage provider with READ_ONLY / WRITABLE / UNSYNCED edit modes, periodic sync, and a Kerberos bridge |
| Custom logic in a login flow | Actions v2 — Zitadel calls an HTTP endpoint you host, in any language | Authenticator SPI — your Java runs in-process; the running server reports 139 provider interfaces |
| Multi-tenancy | Instances and organizations, in the core product | Realms, or one realm with the open-source Organizations extension |
| Audit trail | Event-sourced: every state change is an event, and the event store is the system of record | Admin and user events in the database; retention and external sinks are configuration |
| Managed option | Zitadel Cloud, billed by daily active users; EU, US, Switzerland and Australia | ✓Any cloud or region you like, or a dedicated cluster at a fixed monthly price |
The arguments that carry a Keycloak comparison against a commercial platform — no per-user licence, no cloud-only deployment, source you can read — all apply to Zitadel too. It is a real open-source identity server, it self-hosts, and it is actively developed: 45 releases published so far in 2026 against Keycloak's 21.
Both of them, verified on the versions above:
So the honest version of this page is not "Zitadel is the cheap option and Keycloak is the real one." Zitadel is genuinely better at several things, and we say which in the last section. What follows is the set of differences that actually change an architecture.
This is the first real fork and the one most comparisons skip. Keycloak is Apache 2.0. Zitadel's server is AGPL-3.0-only, and the repository's own LICENSING.md is the authority on the carve-outs.
| What | Licence |
|---|---|
| Zitadel server | AGPL-3.0-only |
| proto/ and the documentation | Apache 2.0 |
| The login app and the client/proto packages | MIT |
| Inbound contributions | Apache 2.0 only — the project will not accept them under the AGPL it ships |
| All of Keycloak | Apache 2.0 |
For most teams this changes nothing. Running an unmodified Zitadel to log users into your product is use, not distribution. The AGPL's network clause bites when you modify the server and let third parties interact with your modified version over a network. At that point you owe those users the corresponding source, and the licence reaches the "work based on the Program", a boundary that is argued rather than settled. Zitadel's own licensing policy says plainly that determining compliance is your responsibility and recommends legal counsel, and its self-hosting page sells a commercial agreement that replaces the AGPL so that you can, in its words, "keep your modifications private".
That is a reasonable position, and it is also the thing to notice: under AGPL the upstream vendor is the only party who can relieve you of the obligation, and the Apache-2.0-inbound rule is what keeps them able to. Apache 2.0 has no equivalent conversation, and that matters most to exactly the teams who are likeliest to need it: anyone shipping identity inside an appliance, embedding it in a product, or patching the server to fit a regulator.
We started both at their published quickstarts and read the discovery documents. No tuning, no feature flags, defaults only. Keycloak's document carries 56 keys, Zitadel's 29. Reproduce it in two commands:
# Keycloak 26.8.1
curl -s http://localhost:8080/realms/master/.well-known/openid-configuration
# Zitadel v4.20.0
curl -s http://localhost:8080/.well-known/openid-configuration| Advertised at defaults | Zitadel v4.20.0 | Keycloak 26.8.1 |
|---|---|---|
| Authorization code + PKCE | S256 only | S256 and plain |
| Hybrid flow (code id_token) | no | yes |
| Resource owner password grant | no | yes |
| Token exchange (RFC 8693) | not advertised | advertised |
| CIBA | no | yes |
| Pushed authorization requests | no | yes |
| DPoP | no | yes |
| mTLS client auth and bound tokens | no | yes |
| Dynamic client registration | off by default | on |
| iss in the authorization response (RFC 9207) | no | yes |
| Front-channel logout | no | yes |
| ui_locales advertised | 22 locales | not advertised |
Read that table carefully, because a discovery document is not a feature list. Two of those rows prove it in opposite directions. Zitadel does implement RFC 8693 token exchange and RFC 7591 dynamic client registration — the registration endpoint only appears in discovery once it is turned on in the instance's security settings, which is visible in the server source, and token exchange is enabled per application rather than globally. Going the other way, Keycloak advertises the token exchange grant, but the legacy flavour that covers brokering and impersonation is still a preview feature and is disabled unless you ask for it. Both servers can do more than they say, and one of them says more than it does.
What the table is good for is the shape of each project. Keycloak's defaults carry the later OAuth hardening work — PAR, DPoP, mTLS-bound tokens, RFC 9207 — because large regulated deployments ask for it, and it also still ships the password grant, which Zitadel does not and which you should not be using either. Zitadel's defaults are narrower and in two places safer: S256-only PKCE and no ROPC are the choices you would make yourself.
What you actually get for what you actually pay.
| Zitadel | You Keycloak + Phase Two | |
|---|---|---|
| Open source | ||
| Permissive licence (Apache 2.0) | ||
| Vendor-neutral foundation governance | ||
| OIDC, OAuth 2.0 and SAML 2.0 | ||
| PAR, DPoP and mTLS-bound tokens at defaults | ||
| LDAP / AD federation with sync and write-back | ||
| Kerberos desktop SSO | ||
| Full template-level login customization | ||
| Extend without writing Java | ||
| Multi-tenancy in the core product | ||
| Event-sourced audit trail by default | ||
| Runs as one service plus a database | ||
| Managed, in any cloud or region you choose |
Every identity project eventually needs logic that is specific to you: a check against an internal system before a user is created, a claim computed from somewhere else, a step in the login that nobody else has. The two answers are different enough to decide the whole choice.
| Zitadel — Actions v2 | Keycloak — SPI | |
|---|---|---|
| Where your code runs | On an HTTP endpoint you host and operate | Inside the server process |
| Language | Anything that serves a POST | Java, packaged as a JAR |
| To deploy a change | Deploy your endpoint. Zitadel is untouched | Rebuild and restart the server |
| Cost on the login path | A network round trip, plus the failure modes of one | A method call |
| Reach | The request, the response, defined functions and events | 139 provider interfaces on the running server — storage, authenticators, mappers, policies |
| What breaks on upgrade | Your contract with a documented API | Your JAR, against internal interfaces that are not a stable API |
If your team does not write Java, Zitadel's model is the better one and it is not close. Nothing in the server has to be rebuilt, the blast radius of a bad action is an endpoint you can roll back, and a Go or TypeScript shop stays in its own language.
The price is that the extension point is now a service: it needs to be deployed, kept up, authenticated, and kept fast enough to sit in a login. If it is down, the thing it was guarding is down with it. Keycloak's answer has the opposite shape: nothing extra to operate, no round trip, and far deeper access to the model, in exchange for writing Java and for a provider that can break on an upgrade because the SPIs it binds to are internal. One is an integration problem, the other is a maintenance problem. Pick the one your team already knows how to carry.
If every user will be created in the new system, skip this section. If they live in Active Directory or an LDAP server today, it is probably the deciding one.
Zitadel treats LDAP as an identity provider. Its own documentation describes the login sequence: connect, bind with the service account, search for the user DN, bind again as that user with the submitted password, map attributes. It is authentication at login time. It is correct, simple, and tied to the LDAP server being reachable at the moment someone signs in.
Keycloak treats LDAP as user storage, which is a different thing. Users are imported or read through, and the provider's edit mode decides which way writes flow:
On top of that sit LDAP mappers for groups and roles, a periodic full sync and a changed-users sync, and a Kerberos bridge for desktop single sign-on. Verified against the Keycloak 26.8.1 server administration guide.
The practical difference: an organization with an existing directory, group-derived authorization and desktop SSO gets all of that from Keycloak as configuration. With Zitadel the login works and the rest is yours to build, through the provisioning APIs, SCIM, or an action. Our Keycloak identity provider documentation covers the brokering side, and SCIM explained covers the provisioning side.
Zitadel is the better answer when:
Keycloak earns it when:
And the honest closing note, which applies to either choice: the operations bill is real. Keycloak is a JVM application with a database, a cache and an upgrade cadence, and running it well is a job. That is the argument for managed Keycloak at a fixed monthly price rather than a per-user meter. If you would rather run it yourself, we also support teams who do. If residency is driving the decision, our EU data residency page states where identity data sits and where it does not, including the parts that are not flattering.
Moving between two standards-based identity servers is mostly client configuration and a user import. The expensive parts are the custom logic and whatever your directory is doing. We will tell you plainly which of the two fits, including when the answer is not us.
See how we migrate teams to KeycloakMulti-region, high-availability Keycloak with 100+ extensions. Simple, cost-conscious, and customizable.
Run your own Keycloak? Get expert escalation, security patches, and architecture guidance — at any level of complexity.
Yes, and unusually for this page the comparison is close. Zitadel is a genuine open-source identity server with OIDC, OAuth 2.0, SAML and SCIM, a much smaller runtime footprint, multi-tenancy in the core product, and an extension model that does not require Java. Keycloak answers back with Apache 2.0 licensing, LDAP and Active Directory federation with write-back and scheduled sync, Kerberos, a broader OAuth surface at its defaults, and CNCF governance with many independent vendors behind it. Teams with an existing directory, or who embed or modify the server, usually land on Keycloak.
Zitadel's server is licensed AGPL-3.0-only, with its proto definitions and documentation under Apache 2.0 and its login app and client packages under MIT. For a team running an unmodified Zitadel as its identity provider, the licence changes nothing. It matters when you modify the server and let third parties use the modified version over a network, or when you redistribute or embed it: then AGPL obligations attach, and Zitadel sells a commercial licence as the alternative. Keycloak is Apache 2.0 throughout, which has no equivalent condition.
Not in the same way. Zitadel configures LDAP as an identity provider: at login it binds with a service account, searches for the user, binds again with the submitted password, and maps attributes. Keycloak configures LDAP and Active Directory as user storage, with READ_ONLY, WRITABLE and UNSYNCED edit modes, mappers for groups and roles, periodic full and changed-user synchronization, and a Kerberos bridge for desktop single sign-on. If your authorization is derived from directory groups, that difference is most of the project.
Zitadel, measurably. Idle and immediately after start on a 2-CPU, 8 GB machine, the four containers of Zitadel v4.20.0's published compose stack used about 249 MB in total, and Keycloak 26.8.1's quickstart container about 611 MB. Two caveats: Keycloak sizes its JVM heap from the memory limit it is given, so that number moves with the limit, and the Keycloak figure is development mode with an embedded database while the Zitadel figure includes a real PostgreSQL. Neither is a production sizing, but a Go binary is lighter than a JVM and will stay that way.
Up to a point. Zitadel's console covers logo, colours, font and a watermark toggle, per instance or per organization. Beyond that the route is to fork its login application, a separate Next.js service under the MIT licence, and run your own. Keycloak themes override any template, message bundle or asset in the login, account and email flows, and deploy into the server with no extra service to operate. Which is better depends on whether a second deployable is a cost or a feature for you.
Not in the core product. Zitadel has instances and organizations built in. Keycloak gives you realms, which are isolated but heavy, and a realm per customer stops scaling long before a SaaS tenant list does. The workable Keycloak pattern is one realm with organizations inside it, which is why we build and maintain an open-source organizations extension with SCIM 2.0 provisioning. If multi-tenancy is the whole product and you are starting from nothing, this is the strongest argument on Zitadel's side.