What is an OTP?

An OTP (One-Time Password) is a temporary code generated for user verification. It is commonly used for:

  • Phone verification
  • Email verification
  • Password reset
  • Two-Factor Authentication (2FA)
  • Login verification

Since OTPs are only valid for a short period (usually 30 seconds to 10 minutes), they have different storage requirements than permanent user data.

Why Redis is Perfect for OTP Storage

Redis is an in-memory data store designed for speed and temporary data.

1. Extremely Fast

Redis stores data in RAM instead of reading from disk.

This means:

  • Read operations happen in microseconds.
  • Write operations are almost instantaneous.
  • Perfect for authentication systems handling thousands of requests per second.

Example:

User requests OTP
        ↓
Store OTP in Redis
        ↓
User submits OTP
        ↓
Verify in Redis
        ↓
Delete OTP

The entire process is incredibly fast.

2. Built-in Expiration (TTL)

One of Redis's greatest features is automatic expiration.

Instead of manually deleting expired OTPs, simply set a TTL (Time To Live).

Example:


await redis.set(
    `otp:${userId}`,
    otp,
    {
        EX: 300 // expires after 5 minutes
    }
);

After 5 minutes, Redis automatically removes the OTP.

No cron jobs.

No cleanup scripts.

No database maintenance.

3. Automatic Cleanup

Imagine sending one million OTPs daily.

If stored in a database, you'll accumulate one million new rows every day.

Soon you'll need:

  • Cleanup scripts
  • Scheduled jobs
  • Additional indexing
  • Storage optimization

Redis handles this automatically through expiration.

4. Better Performance Under Heavy Load

High-traffic applications constantly generate OTPs.

Examples include:

  • Banking apps
  • Ride-sharing platforms
  • Food delivery services
  • Social media
  • E-commerce websites

Redis easily handles hundreds of thousands of operations per second.

Traditional databases become slower as tables grow.

5. Reduced Database Load

Databases should focus on storing long-term information:

  • Users
  • Orders
  • Transactions
  • Products
  • Payments

OTPs are temporary.

Keeping them in Redis prevents unnecessary writes to your primary database.

Why Storing OTPs in a Database Isn't Ideal

Although storing OTPs in MySQL, PostgreSQL, or MongoDB works, it's usually not the best design.

Some drawbacks include:

Permanent Storage

Databases are designed for persistent data.

OTPs should disappear after a few minutes.

Extra Cleanup Required

You'll need scheduled jobs like:


DELETE FROM otp_codes
WHERE expires_at < NOW();

This creates additional maintenance.

Increased Storage

Millions of expired OTPs consume storage unnecessarily.

Slower Queries

As the OTP table grows, searches become slower unless proper indexing is maintained.

Security Best Practices

Regardless of where OTPs are stored, follow these practices.

Hash OTPs

Instead of storing:

123456

Store:

SHA256(123456)

This prevents attackers from reading OTPs if Redis or the database is compromised.

Limit Verification Attempts

Allow only 3–5 attempts.

Example:

Attempt 1 ✅

Attempt 2 ✅

Attempt 3 ❌

Account temporarily blocked

Redis can easily track attempts with counters.

Use Short Expiration Times

Recommended TTL:

  • Email OTP: 5–10 minutes
  • SMS OTP: 2–5 minutes
  • Login OTP: 30–120 seconds

Delete OTP After Success

Even if TTL hasn't expired, remove the OTP immediately after successful verification.

When Should You Use a Database?

A database is appropriate when you need:

  • OTP audit logs
  • Compliance records
  • Analytics
  • Historical verification reports

A common production architecture looks like this:

Redis
│
├── Active OTP
├── Retry Count
├── Rate Limit
└── Auto Expire

Database
│
├── Verification History
├── Audit Logs
├── Login Records
└── Security Events

Redis handles active OTPs, while the database stores historical information.

Redis OTP Example (Node.js)


const otp = "834291";

await redis.set(
    `otp:${userId}`,
    otp,
    {
        EX: 300
    }
);

const storedOtp = await redis.get(`otp:${userId}`);

if (storedOtp === otp) {
    await redis.del(`otp:${userId}`);
}

This implementation is clean, efficient, and production-ready.

Final Recommendation

For almost every modern application, Redis is the best solution for storing OTPs. Its lightning-fast performance, built-in expiration, and automatic cleanup make it ideal for temporary authentication data.

Traditional databases are better suited for permanent records, while Redis excels at handling short-lived, high-speed data like OTPs.

If you're building a secure authentication system, the recommended architecture is simple:

  • Store active OTPs in Redis
  • Store verification history and audit logs in your database
  • Hash OTPs before storing
  • Use TTL for automatic expiration
  • Delete OTPs immediately after successful verification
  • Implement rate limiting and retry limits

By combining Redis with your primary database, you get the best balance of performance, scalability, security, and maintainability.

FAQ

Is Redis better than MongoDB for OTP storage?

-Yes. Redis is specifically designed for temporary, high-speed data with automatic expiration, making it a better choice for OTP storage than MongoDB.

Should I hash OTPs before storing them?

-Yes. Hashing OTPs adds an extra layer of security in case your storage system is compromised.

How long should an OTP remain valid?

-Most applications use 2–5 minutes for SMS OTPs and 5–10 minutes for email OTPs.

Can I use both Redis and a database?

-Absolutely. Store active OTPs in Redis and keep verification logs or audit history in your database. This is the architecture used by many production systems.