Architecture¶
Component topology, deployment patterns, data model, and API surface of Zitadel.
Component Topology¶
flowchart TB
subgraph Clients["Client Applications"]
Browser["Browser\n(Login UI)"]
Console["Console\n(Angular Admin UI)"]
Apps["Your Applications\n(Web, Mobile, API)"]
end
subgraph Zitadel["Zitadel Server (Go Binary)"]
direction TB
APIGW["API Gateway\n(connectRPC / gRPC / REST)"]
subgraph Services["Domain Services"]
AuthSvc["Authentication\nService"]
UserSvc["User\nService"]
OrgSvc["Organization\nService"]
ProjSvc["Project\nService"]
SessSvc["Session\nService"]
ActSvc["Actions\nService"]
end
subgraph Core["Core Engine"]
Cmd["Command Handlers\n(Write Path)"]
Query["Query Handlers\n(Read Path)"]
ES["Eventstore\n(Events2 Table)"]
ProjW["Projection\nWorkers"]
end
subgraph Ext["Extensibility"]
Actions["JS Actions\nRuntime"]
Hooks["Webhook\nDispatcher"]
SCIM["SCIM 2.0\nServer"]
end
end
subgraph Data["Data Layer"]
PG["PostgreSQL\n(Events + Projections)"]
Redis["Redis\n(Query Cache)"]
end
subgraph External["External Systems"]
IdP["Identity Providers\n(Google, GitHub, Azure AD)"]
SMTP["SMTP / SMS\n(Notifications)"]
OTel["OpenTelemetry\nCollector"]
end
Browser --> APIGW
Console --> APIGW
Apps --> APIGW
APIGW --> Services
Services --> Core
Cmd --> ES
ProjW --> ES
Query --> Redis
ProjW --> PG
ES --> PG
Query --> PG
APIGW --> Ext
Actions --> Hooks
SCIM --> UserSvc
AuthSvc --> IdP
ActSvc --> SMTP
APIGW --> OTel
style Zitadel fill:#1565c0,color:#fff
style Data fill:#2e7d32,color:#fff
style External fill:#e65100,color:#fff
Monolithic Binary, Modular Internals¶
Zitadel ships as a single Go binary with modular internal packages:
| Package | Purpose |
|---|---|
internal/eventstore/ |
Event store abstraction, PostgreSQL implementation, push/pop logic |
internal/command/ |
Write-side command handlers, business rule validation |
internal/query/ |
Read-side query handlers, projection consumers |
internal/auth/ |
OIDC, OAuth 2.0, SAML 2.0 protocol implementations |
internal/authz/ |
Authorization resolution, permission checking |
internal/api/ |
gRPC/REST API layer, connectRPC integration |
internal/actions/ |
JavaScript runtime for custom auth flows |
internal/crypto/ |
Encryption, hashing, key management |
internal/webauthn/ |
FIDO2/WebAuthn authentication |
internal/notification/ |
Email, SMS delivery pipeline |
internal/idp/ |
External identity provider integrations |
internal/user/ |
User domain logic (human + machine) |
internal/org/ |
Organization domain logic |
internal/project/ |
Project, application, role management |
internal/i18n/ |
Internationalization |
internal/cache/ |
Redis caching abstraction |
API Surface¶
Zitadel exposes a dual-versioned API surface:
V1 APIs (Legacy, Context-Based)¶
| API | Scope | Base Path | Purpose |
|---|---|---|---|
| Auth API | Per-user | /auth/v1/ |
User-specific ops (profile, tokens, MFA) |
| Management API | Per-org | /management/v1/ |
Org admin ops (users, projects, apps) |
| Admin API | Instance-wide | /admin/v1/ |
Instance-level configuration |
| System API | Self-hosted | /system/v1/ |
Superordinate control |
V2 APIs (Current, Resource-Oriented)¶
| API | Base Path | Purpose |
|---|---|---|
| User Service | /v2/users/ |
User management (preferred for new integrations) |
| Session Service | /v2/sessions/ |
Session lifecycle management |
| Organization Service | /v2/orgs/ |
Organization management |
| Project Service | /v2/projects/ |
Projects, apps, roles |
| Action Service | /v2/actions/ |
Actions and webhooks |
| Feature Service | /v2/features/ |
Feature flag management |
| Settings Service | /v2/settings/ |
Login, password, branding policies |
| Authorization Service | /v2/authorizations/ |
User authorization (grants) |
| OIDC Service | Standard OIDC endpoints | OpenID Connect operations |
| SAML Service | Standard SAML endpoints | SAML 2.0 operations |
| SCIM 2.0 | /scim/v2/{orgID}/ |
User provisioning |
| Web Key Service | /v2/webkeys/ |
JWT signing key management |
API Conventions¶
| Operation | Method | Pattern |
|---|---|---|
| Create | POST | /v2/<resource> |
| Update | POST | /v2/<resource>/<id> |
| Delete | DELETE | /v2/<resource>/<id> |
| Set | PUT | /v2/<resource> |
| Get | GET | /v2/<resource>/<id> |
| Search | POST | /v2/<resource>/search |
All APIs are generated from Protocol Buffer definitions in proto/zitadel/. The server supports connectRPC, standard gRPC, and HTTP/1.1 simultaneously.
Data Model¶
Hierarchical Resource Model¶
erDiagram
INSTANCE ||--o{ ORGANIZATION : contains
ORGANIZATION ||--o{ USER : manages
ORGANIZATION ||--o{ PROJECT : owns
ORGANIZATION ||--o{ IDP_CONFIG : configures
ORGANIZATION ||--o{ POLICY : enforces
PROJECT ||--o{ APPLICATION : registers
PROJECT ||--o{ ROLE : defines
PROJECT ||--o{ PROJECT_GRANT : shares
USER ||--o{ USER_GRANT : receives
USER ||--o{ SESSION : creates
USER ||--o{ IDP_LINK : links
PROJECT_GRANT }o--|| ORGANIZATION : "granted to"
USER_GRANT }o--|| PROJECT : "scoped to"
USER_GRANT }o--|| USER : "assigned to"
ROLE }o--|| USER_GRANT : "included in"
INSTANCE {
string instance_id PK
string domain
}
ORGANIZATION {
string org_id PK
string name
string state
}
USER {
string user_id PK
string org_id FK
string type
string state
string email
string phone
}
PROJECT {
string project_id PK
string org_id FK
string name
string state
}
APPLICATION {
string app_id PK
string project_id FK
string name
string type
}
ROLE {
string role_key PK
string project_id FK
string display_name
string group
}
PROJECT_GRANT {
string grant_id PK
string project_id FK
string granted_org_id FK
string state
}
USER_GRANT {
string grant_id PK
string user_id FK
string project_id FK
string org_id FK
}
Eventstore Schema¶
The eventstore uses a custom PostgreSQL schema optimized for append-only operations:
| Table | Purpose |
|---|---|
eventstore.events2 |
Immutable event log with composite PK (aggregate_id, sequence) |
eventstore.unique_constraints |
Enforces uniqueness across events (e.g., unique email per instance) |
projections.* |
Materialized read-model tables rebuilt from events |
Events are inserted atomically via the eventstore.push PostgreSQL function, which handles sequence assignment and unique constraint checking in a single transaction.
Deployment Topologies¶
Single Instance (Development)¶
flowchart LR
subgraph Host["Docker Host"]
ZA["Zitadel\n:8080"]
PG["PostgreSQL 17\n:5432"]
end
ZA --> PG
Kubernetes Production (HA)¶
flowchart TB
subgraph LB["Load Balancer"]
NGINX["NGINX Ingress\n(TLS Termination)"]
end
subgraph K8s["Kubernetes Cluster"]
subgraph ZA["Zitadel Pods (HPA)"]
Z1["zitadel-7d4f8"]
Z2["zitadel-a3b2c"]
Z3["zitadel-e9f1g"]
end
Init["Init Job\n(DB Migrations)"]
Setup["Setup Job\n(Schema + Defaults)"]
subgraph Data["Data Plane"]
PGHA["PostgreSQL HA\n(Patroni / CloudSQL / RDS)"]
Redis["Redis\n(Cache)"]
end
end
NGINX --> Z1
NGINX --> Z2
NGINX --> Z3
Z1 --> PGHA
Z2 --> PGHA
Z3 --> PGHA
Z1 --> Redis
Z2 --> Redis
Z3 --> Redis
style K8s fill:#1565c0,color:#fff
style Data fill:#2e7d32,color:#fff
Multi-Cluster / SaaS¶
flowchart TB
subgraph Cloud["Zitadel Cloud"]
ZC["Managed Zitadel\nInstance"]
PG_C["Managed PostgreSQL"]
end
subgraph Remote1["Remote App Cluster 1"]
App1["Application A"]
end
subgraph Remote2["Remote App Cluster 2"]
App2["Application B"]
end
App1 -->|"OIDC / SAML"| ZC
App2 -->|"OIDC / SAML"| ZC
ZC --> PG_C
style Cloud fill:#1565c0,color:#fff