ZITADEL

Cloud-native identity infrastructure with multi-tenancy built

Identity & SSO ★ 15.1k stars Medium setup Apache-2.0

ZITADEL is an open-source identity and access management platform built for multi-tenant applications. It offers OpenID Connect, OAuth2, SAML, passwordless login and a powerful management API.

Key features

  • Multi-tenancy as a first-class concept
  • Passwordless and FIDO2 authentication
  • Event-sourced audit trail
  • Comprehensive gRPC and REST APIs

Pros & cons

Strengths

  • Strong multi-tenant model
  • Modern Go codebase

Trade-offs

  • Smaller community than Keycloak

ZITADEL replaces

Last reviewed Aug 26, 2026 · 817 words

Pick ZITADEL over Keycloak when the thing you are building has customers who each need their own users, roles and branding. Pick something lighter than both when all you want is a login page for a homelab. That is the whole decision, and it is worth stating up front because ZITADEL's marketing, its Auth0 comparison and its 14,900 GitHub stars all draw self-hosters who then discover they have deployed a B2B identity platform to protect a Jellyfin instance. It is Apache-2.0, written in Go, first released in 2020, and it needs only PostgreSQL and about 512 MB to run, which makes it the most modern of the serious identity servers by a distance.

Multi-tenancy is the data model, not a feature

Everything hangs off an instance, which contains organizations, which contain users, and projects, which contain applications and roles. A project in one organization can be granted to another, so the software company's app lives in its org while each customer org manages its own users, its own login policy, its own SSO federation and its own branding, and their users get the customer's roles in the vendor's project. Keycloak models this with realms and it works, but realms are isolated silos and sharing an application across them is awkward. If your product has tenants, ZITADEL's shape matches the problem. If it does not, this structure is overhead you carry for nothing.

Setup is PostgreSQL, one container and a master key

services:
  zitadel:
    image: ghcr.io/zitadel/zitadel:latest
    command: start-from-init --masterkeyFromEnv --tlsMode external
    environment:
      ZITADEL_MASTERKEY: MasterkeyNeedsToHave32Characters
      ZITADEL_EXTERNALDOMAIN: auth.example.com
      ZITADEL_EXTERNALSECURE: "true"
      ZITADEL_EXTERNALPORT: 443
      ZITADEL_DATABASE_POSTGRES_HOST: db
      ZITADEL_DATABASE_POSTGRES_PORT: 5432
      ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel
      ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel
      ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: zitadel
      ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable
      ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: postgres
      ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: postgres
      ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable
    ports:
      - "8080:8080"
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: postgres
    volumes:
      - ./pg:/var/lib/postgresql/data

Three things break first installs. The master key must be exactly 32 characters, it encrypts secrets at rest, and losing it means starting over; the example value above is the one from the docs and you replace it. The external domain, port and secure flag must match the address users will type, because every token issuer URL, redirect and login link is derived from them, and changing the domain later is a migration, not a setting. And tlsMode external means the reverse proxy terminates TLS, which is fine, but that proxy must speak HTTP/2 to the backend because the management console uses gRPC-web; Caddy does this by default and Nginx needs grpc_pass for the API paths. On first start the admin user is created under the instance's default organization and the console prompts for a password change.

Event sourcing gives you an audit trail and a growing database

Every change in ZITADEL is an immutable event, and the current state is a projection over those events. The upside is a complete audit history of who changed what, plus the ability to rebuild projections after an upgrade. The downside is that the events table only grows, projections consume CPU on every write, and a busy instance needs PostgreSQL tuned like a real database rather than a side container. For a homelab this never matters. For 100,000 users it is the section of the docs to read before sizing the server.

What you get that Keycloak and Authentik do not

Passkeys and FIDO2 passwordless login are first-class rather than bolted on. The API is gRPC with a REST gateway covering every operation the console can do, with a Terraform provider on top, so an organization, its admin and its SSO configuration can be created from a script. Actions let you run JavaScript at login and token creation to add claims or call an external system. Recent versions move the login UI into a separate service, so check which layout your version expects before copying an older compose file. What you do not get is the Authentik proxy outpost that puts a login in front of apps with no OIDC support, or Authelia's tiny footprint and per-path rules; for a homelab those two cover more of the actual problem. Keycloak keeps its advantage in community size, in the sheer number of adapters and tutorials, and in the volume of enterprise SAML edge cases it has already met.

What I'd do

Building a product with customer organizations, or an internal platform for several teams that each own their users: ZITADEL, on PostgreSQL 16 with a real backup schedule, behind Caddy, master key in the password manager. Protecting a homelab of 15 apps: Authentik, or Authelia if memory is tight, and the rest of the identity category is mostly variations on that call. Replacing Auth0 for an app you are shipping: ZITADEL first, Keycloak if your integrators already know it.

Compare ZITADEL

28 head-to-head comparisons.

Similar identity & sso apps