Storing OTPs: Redis vs SQL Database
Trade-offs between Redis and SQL for OTP request data. Latency, durability, audit, retention, and a recommended hybrid pattern that uses both.
StartMessaging Team
Engineering
Redis and SQL serve different needs in OTP storage. Most production systems use both: Redis for the active window, SQL for the audit.
Redis Pros
- Sub-ms latency on read.
- Native TTL — auto-expire after 10 min.
- Atomic INCR for attempt counters.
SQL Pros
- Durable — survives Redis crash.
- Long-term retention for audit (7+ years).
- Joinable with user / session tables.
Recommended Hybrid
- Redis: active OTP request (10-min TTL), attempt counters, rate-limit buckets.
- SQL: audit row written on send and updated on verify.
Patterns
// On send:
await redis.set(`otp:${requestId}`, JSON.stringify(meta), 'EX', 600);
await db.insert('otp_audit').values({ requestId, status: 'sent', ... });
// On verify:
const meta = await redis.get(`otp:${requestId}`);
// ... verify with provider ...
await redis.del(`otp:${requestId}`);
await db.update('otp_audit').set({ status: 'verified', verifiedAt: now }).where({ requestId });FAQ
See our schema guide for the SQL side.
Related Articles
Database schema patterns for storing OTP request metadata: required columns, indexes, retention, hashing, and the columns you should never have.
Yes, always — and bcrypt or scrypt, not SHA-256. Why hashing OTPs matters even though they're short-lived, and concrete code patterns.
Learn proven rate limiting strategies for OTP APIs: per-phone, per-IP, and sliding window approaches to prevent SMS pumping and brute force attacks.
Ready to Send OTPs?
Integrate StartMessaging in 5 minutes. No DLT registration required.