Inconsistent state when creating users in ZITADEL + local DB (NestJS + Drizzle ORM)
I’m facing an issue where a user is successfully created in ZITADEL, but the insert into my PostgreSQL database (via Drizzle ORM) fails.
This leaves me with a user that exists in ZITADEL but not in my local DB.
To handle this, I tried creating the user in my DB first with a status = "pending" (waiting for confirmation), then calling ZITADEL, and finally updating the status to "active".
However, if the status update fails, I end up with garbage data — the user exists in both systems but the local record stays stuck in "pending" state.
Wrapping both operations in a Drizzle transaction doesn’t help since ZITADEL is an external service.
Has anyone experienced this kind of inconsistency between ZITADEL and their own DB?
What’s the recommended way to handle this properly?
1 Reply
Hi @キリト, I'm an AI assistant for ZITADEL. While a team member reviews this question, I'll see if I can find relevant sources for your question.
Answer
I wasn't able to find a direct answer in the ZITADEL documentation about handling distributed transaction patterns between ZITADEL and external databases.
However, based on general distributed systems patterns, you'd typically handle this with one of these approaches:
1. Create in your DB first, then ZITADEL - If your DB insert fails, you never call ZITADEL. If ZITADEL fails, you can roll back your DB transaction.
2. Idempotency + retry logic - Store the ZITADEL user ID in your DB insert. If the DB insert fails after ZITADEL creation, retry the DB insert with the same ZITADEL user ID.
3. Event-driven reconciliation - Use ZITADEL's Events API (1) to pull audit logs and reconcile your local DB state. You can filter for specific event types like "user created" and ensure your DB reflects ZITADEL's state.
4. Saga pattern - Implement compensating transactions where if your DB insert fails, you delete the ZITADEL user.
For monitoring and reconciliation, ZITADEL provides an Events API that lets you pull audit logs with filters for event types, aggregates, and time frames . This could help you identify and fix inconsistencies.
Would you like me to suggest a general implementation approach for one of these patterns?
To learn more, see the sources I considered:
[1] Streaming audit logs to external systems (SIEM/SOC)
Feel free to tag @Ask Inkeep with additional questions.