Both Redis and Postgres backends ship with
@key0ai/key0. They provide identical atomic guarantees — Redis via Lua scripts, Postgres via serializable transactions.
Choosing a backend
- Redis
- Postgres
Use Redis when you want:
- Sub-millisecond latency on reads and writes
- Simple infrastructure (single Redis instance or cluster)
- Automatic key expiration via TTLs
SET NX for transaction dedup, and runs Lua scripts for atomic compare-and-swap state transitions.Setup
Configuration options
RedisChallengeStore accepts a RedisStoreConfig object:RedisSeenTxStore and RedisAuditStore accept only redis and keyPrefix.Key naming
All keys are prefixed withkeyPrefix (default key0):TTL behavior
Atomic transitions
State transitions use a Lua script that runs entirely within Redis. The script:- Reads the current state (compare)
- Writes the new state and field updates (swap)
- Maintains the
key0:paidsorted set (add on PAID, remove on exit from PAID) - Appends an audit entry to the challenge’s audit list
Health check
CallhealthCheck() at startup to fail fast on misconfiguration:IAuditStore
The audit store is optional but recommended for production. Every state transition is logged with:challengeIdandrequestIdfor correlationfromStateandtoStatefor the transitionactor(e.g.,"engine","cron","admin")reason(optional, e.g.,"challenge_created","payment_verified")updates(the field changes applied in the transition)createdAttimestamp
RedisAuditStore and PostgresAuditStore implement IAuditStore. In addition, RedisChallengeStore and PostgresChallengeStore automatically write audit entries during create() and transition() calls — even without a standalone audit store configured.
Standalone (Docker) storage
When running Key0 as a standalone Docker container, set theSTORAGE_BACKEND environment variable to select your backend:
Redis is always required in standalone mode, even when using Postgres as the primary storage backend. The BullMQ-based refund cron job uses Redis as its queue broker.
Connection health
For Redis, callstore.healthCheck() before accepting traffic. For Postgres, the auto-migration step serves as an implicit health check — if it fails, the store constructor’s internal ready promise rejects, and subsequent operations throw.
