# ZITADEL: self-hosted identity infrastructure with instances, organizations and an event stream

> ZITADEL is an open-source IAM platform in Go, AGPL-3.0 licensed, built around a strict tenant hierarchy and an API-first surface. Here is what it actually solves, how the pieces fit, and where it stops being the right tool.

**zitadel/zitadel** — ZITADEL - Identity infrastructure, simplified for you.

- Repository: https://github.com/zitadel/zitadel
- Website: https://zitadel.com
- Stars: 15,139 · Forks: 1,328
- Language: Go
- License: AGPL-3.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/zitadel-zitadel

## What ZITADEL solves, and who it is actually for

Most auth libraries give you a login form and a session. ZITADEL is aimed at the layer above that: an organization selling a B2B SaaS product where each customer needs its own users, its own identity providers, its own branding and its own policy, all inside one deployment. The README frames the differentiator as multi-tenancy, with a hierarchy it describes as Identity System, Organizations and Projects, and with data isolation and policy scoping at multiple levels. On top of that it lists SSO, MFA, passkeys, OIDC, SAML and SCIM as built-in rather than add-on features.

The intended reader is a platform or backend team that has outgrown bolting auth onto an application and now needs a service it can run, version and audit. The README also states that ZITADEL Cloud and self-hosted ZITADEL run the same codebase, which matters if you want to prototype on the hosted offering and later move the same configuration on-premise. If you are building a single-tenant internal tool with a handful of users, most of this design is weight you will pay for and never use.

## Instances, organizations and the event stream underneath

The architecture has two layers that are easy to confuse. The relational core stores current state, and the README describes the other half as event-driven: every mutation is written as an immutable event, producing what it calls a complete, API-accessible audit trail that can be streamed to external systems via webhooks. That is a real design commitment. It means state is derivable from a log rather than only from tables, and it means audit is a first-class output rather than a side table some code paths forget to write.

The tenancy model is the second commitment. The README distinguishes infrastructure-level tenants, which it calls Instances, from B2B Organizations, and its comparison table marks Keycloak realms as having scaling limits where ZITADEL claims high scale for instances. Whether that holds for your workload is something only your own load test settles, but the structural difference is genuine: an instance is a boundary above organizations, not a synonym for one.

Above that sits the API. ZITADEL exposes resources over connectRPC, gRPC and HTTP/JSON, and the README claims every resource and action is reachable that way. The repository layout supports the claim: proto/, openapi/, buf.gen.yaml and buf.work.yaml are all at the top level, so the API surface is generated from schema files rather than hand-written per transport.

## Installing ZITADEL with Docker Compose and creating your first user

The README's quick start downloads a compose file and an environment example from the main branch, copies the example into place, and starts the stack. It claims this gets you up and running in under three minutes. Run it from an empty directory:

```bash
curl -LO https://raw.githubusercontent.com/zitadel/zitadel/main/deploy/compose/docker-compose.yml \
  && curl -LO https://raw.githubusercontent.com/zitadel/zitadel/main/deploy/compose/.env.example \
  && cp .env.example .env \
  && docker compose up -d --wait
```

The --wait flag makes Compose block until containers report healthy, so a returned prompt means the services came up rather than merely started. Read .env before exposing anything: the example file is the only place the README points at for local configuration, and the compose file is pulled from main, not from a tagged release, so pinning it to a release tag is a decision you make yourself.

Once the stack is running, the README's integration example creates a human user through the v2 REST API. It assumes you already hold an access token and know your deployment's domain:

```bash
curl -X POST https://$ZITADEL_DOMAIN/v2/users/human \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "alice@example.com",
    "profile": { "givenName": "Alice", "familyName": "Smith" },
    "email": { "email": "alice@example.com", "sendCode": {} }
  }'
```

The sendCode object is what triggers the verification email, so an empty object is not a no-op. Set ZITADEL_DOMAIN to your instance host and ACCESS_TOKEN to a token with permission to write users. The README does not spell out how to obtain that first token; for that step it defers to the quickstart guide and the API reference on zitadel.com. For Kubernetes instead of Compose, the README links a separate deployment guide.

## The AGPL-3.0 boundary and what it means for a closed product

ZITADEL is licensed AGPL-3.0, and the repository carries both LICENSE and LICENSING.md at the top level. The README markets the project as having no vendor lock-in, and for the code that is accurate. The licence is the part teams skip reading, and it is the part that decides whether self-hosting is viable for a proprietary product.

AGPL-3.0 is a copyleft licence with a network clause. If you modify ZITADEL and let users interact with it over a network, the obligations attach to that deployment in a way that plain GPL does not. Running the unmodified official image as a separate service is a different situation from forking the login flow into your own binary. The presence of LICENSING.md suggests the project documents its own position on this, so read that file rather than a blog post, and treat the question as one for your own counsel. Nothing here is legal advice, and the practical answer depends on how you ship the software.

One operational consequence is easier to state: if your business model depends on keeping your identity layer closed and embedded, verify the licence position before you write integration code, not after. The cost of switching later is measured in migrated user records and re-issued credentials.

## Where ZITADEL is the wrong choice

The first limitation is operational. Self-hosting means owning a Postgres-backed Go service, its upgrades and its availability. The README advertises zero-downtime updates and horizontal scalability without external session stores, and links documentation for updating and scaling, but that documentation describes a procedure you have to execute. A team with no one on call for a stateful service should look hard at whether they want this in their critical path.

The second is the event model's cost. An append-only event stream grows. The README presents the comprehensive audit trail as an advantage over systems that log only select activities, and it is, but comprehensive means storage and retention become your problem. There is no retention or archival policy described in the README.

The third is upgrade cadence. Releases are frequent and versioned semantically: v4.18.0, v4.17.3 and v4.17.2 appear within weeks of each other, and the README links a release cycles and support page. A fast cadence is good for security fixes and bad for teams that want to upgrade twice a year. Check that page before you plan a version policy.

Finally, the README's comparison table is the project's own framing. It marks competitors with partial support in several rows, and those judgements come from the vendor. Treat the table as a list of questions to ask, not as a result.

## Keycloak and Auth0 as the two real alternatives

The most common comparison is Keycloak, and the difference is not feature count. Keycloak's isolation unit is the realm; ZITADEL's is the instance, with organizations nested below. The README's table marks Keycloak realms as having scaling limits where it claims high scale for instances. If you run one realm per customer and have hundreds of customers, that structural difference is the whole argument. Keycloak is also Apache-2.0 licensed, which removes the AGPL question entirely, and it has a longer operational history that many infrastructure teams already know.

The other alternative is a hosted service such as Auth0 or Okta. The README's table marks those as neither open-source nor self-hostable, and notes that multi-tenant there tends to mean multi-account. The trade is the opposite of ZITADEL's: you give up control of the deployment and the data path, and in exchange you give up the pager. For a small team without infrastructure staff, that is often the correct trade, and the README's own positioning does not pretend otherwise. It simply states that ZITADEL Cloud exists in US, EU, AU and CH regions with pay-as-you-go pricing, so the hosted option is available from the same project if you want the model without the operations.

## Maintenance signals and the upgrade surface

The repository is not archived, and the last push was on 2026-09-21, the same day as the v4.18.0 release. That is a project shipping on its own release train, with semantic-release wired in through .releaserc.js and changelog.config.js at the top level. The presence of SECURITY.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md and MEETING_SCHEDULE.md indicates a project that expects outside contributors and has a stated process for them.

The upgrade surface is larger than a single binary. The repository contains a Go backend, a console, an apps/ directory, proto definitions, openapi specs and a pnpm workspace with nx for task orchestration. A self-hosted operator mainly touches the deploy directory and the database migrations, but anyone building on the API should track the proto and openapi directories, because those define the contract you compile against. The README does not document rollback, so a downgrade path is something to establish from your own database backups before you need it.

On licence cost, the code is free under AGPL-3.0 and the README points to professional support for self-hosted deployments as a paid option. That is the commercial model: the software is open, the operational help is not.

## Conclusion

Adopt ZITADEL if you need self-hosted SSO with a real tenant hierarchy and you are willing to run Postgres and a Go service yourself; the Docker Compose path and the v2 REST API are both documented. Do not adopt it if your product is closed source and you cannot live with AGPL-3.0, or if you only need a single-tenant login and want no operational surface at all. Before committing, verify the current release cycle page, read LICENSING.md to see whether your distribution model is covered, and confirm that the Actions v2 webhook model can express the hooks you currently rely on.

## FAQ

### What is ZITADEL used for?

It is an identity and access management platform: the README lists SSO, MFA, passkeys, OIDC, SAML and SCIM as built-in, and positions it for securing a SaaS product or building a B2B platform where each customer needs its own users and policies.

### How does ZITADEL compare to Keycloak?

The README's own table draws the line at tenancy: it describes ZITADEL's isolation unit as infrastructure-level instances with native B2B organizations, and marks Keycloak realms as having scaling limits. Keycloak is Apache-2.0 while ZITADEL is AGPL-3.0, which is a separate decision from the tenancy model.

### Is ZITADEL open source and free?

Yes, the repository is public and licensed AGPL-3.0, with LICENSE and LICENSING.md at the top level. The README also offers ZITADEL Cloud with pay-as-you-go pricing and points to paid professional support for self-hosted deployments.

### How do I install ZITADEL?

The README's quick start downloads deploy/compose/docker-compose.yml and .env.example, copies the example to .env, and runs docker compose up -d --wait. It also links separate deployment guides for Docker Compose and Kubernetes.

### Is ZITADEL self-hosted or only a cloud service?

Both exist. The README states that ZITADEL Cloud and self-hosted ZITADEL run the same codebase, and it links deployment guides for Docker Compose and Kubernetes alongside the hosted offering.

## Sources

- [License: AGPL-3.0](https://github.com/zitadel/zitadel/blob/main/LICENSE)
- [Project website](https://zitadel.com)
- [README](https://github.com/zitadel/zitadel/blob/main/README.md)
- [Releases](https://github.com/zitadel/zitadel/releases)
- [zitadel/zitadel on GitHub](https://github.com/zitadel/zitadel)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zitadel-zitadel
