Redis for Node.js Backend Developers: Caching, Rate Limiting, and More

Redis for Node.js Backend Developers: Caching, Rate Limiting, and More

# redis# database# node
Redis for Node.js Backend Developers: Caching, Rate Limiting, and MoreKrati Joshi

If you're preparing for a Node.js backend interview, Redis is one of those technologies you should...

If you're preparing for a Node.js backend interview, Redis is one of those technologies you should understand beyond just knowing that it's "fast."

Redis is commonly used for caching, sessions, rate limiting, counters, Pub/Sub, distributed coordination, and fast data access.

In this article, I'll cover the Redis concepts that are especially important for backend development and interviews.


πŸš€ What is Redis?

Redis is an in-memory data store that provides several useful data structures and very fast operations.

Instead of primarily reading every value from disk like a traditional relational database, Redis keeps its working dataset in memory.

A common backend architecture looks like:

Client
   ↓
Node.js / Express API
   ↓
Redis
   ↓
Database
Enter fullscreen mode Exit fullscreen mode

Redis can reduce the number of requests that reach the primary database.


⚑ Why is Redis so fast?

The major reason is that Redis is designed around in-memory data access.

Instead of:

Application β†’ Disk-based Database β†’ Response
Enter fullscreen mode Exit fullscreen mode

we can have:

Application β†’ Redis RAM β†’ Response
Enter fullscreen mode Exit fullscreen mode

This makes Redis especially useful when the same data is requested repeatedly.


πŸ“¦ Redis Data Types

Redis isn't limited to simple key-value strings.

Some important data types are:

Data Type Common Use
String Cache, tokens, counters
Hash User/object data
List Queues, recent items
Set Unique values
Sorted Set Leaderboards/ranking
Stream Event/message processing

String

SET user:1:name "Krati"
GET user:1:name
Enter fullscreen mode Exit fullscreen mode

Hash

HSET user:1 name "Krati" role "Backend Developer"
Enter fullscreen mode Exit fullscreen mode

Hashes are useful when storing multiple fields belonging to an object.

Set

SADD online_users 101
SADD online_users 102
Enter fullscreen mode Exit fullscreen mode

Sets automatically maintain uniqueness.

Sorted Set

ZADD leaderboard 1000 user101
ZADD leaderboard 1500 user102
Enter fullscreen mode Exit fullscreen mode

Useful for rankings and leaderboards.


⏳ TTL β€” Time To Live

When Redis is used as a cache, we usually don't want data to remain forever.

We can set an expiration time:

SET user:1 "some-data" EX 300
Enter fullscreen mode Exit fullscreen mode

The key expires after 300 seconds.

Check the remaining time:

TTL user:1
Enter fullscreen mode Exit fullscreen mode

TTL is important because it helps:

  • Remove old cache data
  • Control memory usage
  • Reduce stale data
  • Automatically clean temporary values

🧠 Cache-Aside Pattern

This is one of the most important Redis concepts for backend interviews.

Suppose we have:

GET /users/101
Enter fullscreen mode Exit fullscreen mode

Instead of querying the database every time:

Request
   ↓
Database
   ↓
Response
Enter fullscreen mode Exit fullscreen mode

we use Redis.

Request
   ↓
Redis
   ↓
Cache HIT β†’ Return data
Enter fullscreen mode Exit fullscreen mode

If Redis doesn't contain the data:

Request
   ↓
Redis
   ↓
CACHE MISS
   ↓
Database
   ↓
Store result in Redis
   ↓
Return response
Enter fullscreen mode Exit fullscreen mode

This is called the Cache-Aside pattern.

The application is responsible for reading and populating the cache.


🎯 Cache Hit vs Cache Miss

Cache Hit

The requested data exists in Redis.

Request
 ↓
Redis
 ↓
HIT
 ↓
Return
Enter fullscreen mode Exit fullscreen mode

The database doesn't need to be queried.

Cache Miss

The requested data isn't present.

Request
 ↓
Redis
 ↓
MISS
 ↓
Database
 ↓
Redis SET
 ↓
Return
Enter fullscreen mode Exit fullscreen mode

A useful metric is:

Cache Hit Ratio =
Cache Hits / (Cache Hits + Cache Misses)
Enter fullscreen mode Exit fullscreen mode

πŸ—‘οΈ Cache Invalidation

One of the hardest problems with caching is keeping cached data consistent with the database.

Suppose:

Database:
User name = Alice

Redis:
User name = Alice
Enter fullscreen mode Exit fullscreen mode

Now the user changes their name:

Database:
Alice β†’ Bob
Enter fullscreen mode Exit fullscreen mode

But Redis still contains:

Alice
Enter fullscreen mode Exit fullscreen mode

Now we have stale cache data.

A common solution is:

UPDATE Database
       ↓
DELETE Redis key
Enter fullscreen mode Exit fullscreen mode

For example:

await db.user.update({
  where: { id },
  data: updateData
});

await redis.del(`user:${id}`);
Enter fullscreen mode Exit fullscreen mode

The next request will cause a cache miss and fetch the latest data from the database.


🟒 Using Redis with Node.js

The official Node.js Redis client is node-redis.

Basic setup:

import { createClient } from "redis";

const redis = createClient({
  url: process.env.REDIS_URL
});

redis.on("error", (err) => {
  console.error("Redis error:", err);
});

await redis.connect();
Enter fullscreen mode Exit fullscreen mode

Set a value:

await redis.set("name", "Krati");
Enter fullscreen mode Exit fullscreen mode

Get it:

const name = await redis.get("name");
Enter fullscreen mode Exit fullscreen mode

Set with TTL:

await redis.set("otp:123", "456789", {
  EX: 300
});
Enter fullscreen mode Exit fullscreen mode

Delete:

await redis.del("otp:123");
Enter fullscreen mode Exit fullscreen mode

🚦 Redis for Rate Limiting

Redis is also very useful for implementing API rate limiting.

Imagine:

POST /login
Enter fullscreen mode Exit fullscreen mode

We want to allow only:

5 attempts / minute
Enter fullscreen mode Exit fullscreen mode

We can maintain a counter in Redis.

Conceptually:

Request
   ↓
Redis INCR
   ↓
Check count
   ↓
Limit exceeded?
   β”œβ”€β”€ YES β†’ Reject
   └── NO  β†’ Continue
Enter fullscreen mode Exit fullscreen mode

Example:

INCR login:user123
EXPIRE login:user123 60
Enter fullscreen mode Exit fullscreen mode

Redis works well here because operations such as INCR are atomic.

It's also shared across multiple Node.js instances:

             β”Œβ”€β”€ Node Server 1
Client ──────┼── Node Server 2
             └── Node Server 3
                    ↓
                  Redis
Enter fullscreen mode Exit fullscreen mode

All servers can use the same rate-limit state.


πŸ” Redis for Sessions

When an application has multiple servers, storing sessions only in one server's memory can become problematic.

Instead:

                β”Œβ”€β”€ Server 1
Client ─────────┼── Server 2
                └── Server 3
                       ↓
                     Redis
Enter fullscreen mode Exit fullscreen mode

All servers can access the same session information.

Redis documentation specifically describes Redis as a useful shared session store for stateless application servers.


πŸ”„ Atomic Operations

An operation is atomic when it executes as one indivisible operation from the perspective of other Redis commands.

For example:

INCR counter
Enter fullscreen mode Exit fullscreen mode

Instead of doing:

GET counter
   ↓
counter + 1
   ↓
SET counter
Enter fullscreen mode Exit fullscreen mode

we can use:

INCR counter
Enter fullscreen mode Exit fullscreen mode

This is especially useful for:

  • Counters
  • Rate limiting
  • Concurrent requests
  • Distributed applications

πŸ“’ Redis Pub/Sub

Redis can also provide a publish/subscribe mechanism.

Architecture:

Publisher
    ↓
Redis Channel
    ↓
Subscribers
Enter fullscreen mode Exit fullscreen mode

Example:

PUBLISH notifications "Order created"
Enter fullscreen mode Exit fullscreen mode

Another service can subscribe:

SUBSCRIBE notifications
Enter fullscreen mode Exit fullscreen mode

Useful for:

  • Notifications
  • Real-time events
  • Lightweight service communication

Important interview point

Redis Pub/Sub is not a durable message queue.

If a subscriber is disconnected, it can miss messages.

For durable event processing, Redis Streams are a better concept to study. Redis Streams support persisted entries and consumer groups.


πŸ’Ύ Redis Persistence: RDB vs AOF

Redis is primarily memory-based, but it supports persistence.

Two important mechanisms are:

RDB

RDB = Redis Database snapshot

Redis periodically creates a point-in-time snapshot of the dataset.

Redis
  ↓
Snapshot
  ↓
Disk
Enter fullscreen mode Exit fullscreen mode

Advantages:

  • Compact
  • Good for backups
  • Efficient snapshot-based recovery

Disadvantage:

  • Changes made after the latest snapshot may be lost after a failure.

AOF

AOF = Append Only File

Instead of only taking periodic snapshots, Redis records write operations in an append-only log.

SET user:1 Alice
INCR counter
DEL user:2
        ↓
       AOF
        ↓
       Disk
Enter fullscreen mode Exit fullscreen mode

When Redis restarts, the recorded operations can be replayed to reconstruct the dataset.

AOF durability depends on its fsync configuration; stronger durability generally comes with more I/O cost.

Quick comparison

RDB AOF
Snapshot Write log
Point-in-time Records changes
Usually more compact Usually larger
Good for backups Better durability options
Can lose recent changes Less data loss depending on fsync

🧹 Redis Eviction

Redis data lives primarily in memory, so memory management is important.

If Redis reaches its configured memory limit, an eviction policy can determine what happens to keys.

Some policies include:

noeviction
allkeys-lru
volatile-lru
allkeys-lfu
Enter fullscreen mode Exit fullscreen mode

Interview question:

What happens when Redis memory is full?

Answer:

Redis applies the configured memory policy. Depending on the policy, it may evict eligible keys or reject writes.


πŸ’₯ Cache Stampede

Consider a popular API:

1000 requests
      ↓
Same cached key
      ↓
Cache expires
      ↓
1000 CACHE MISS
      ↓
1000 Database queries
Enter fullscreen mode Exit fullscreen mode

The database can suddenly become overloaded.

This is called a cache stampede.

Possible solutions:

  • Distributed locking
  • Request coalescing
  • Background refresh
  • TTL jitter
  • Cache warming

πŸ”’ Redis Distributed Lock

Redis can also be used for distributed coordination.

A basic locking concept is:

SET lock:payment 123 NX EX 30
Enter fullscreen mode Exit fullscreen mode

Here:

  • NX β†’ set only if the key doesn't exist
  • EX 30 β†’ lock expires after 30 seconds

This can help ensure that multiple application instances don't simultaneously perform the same critical operation.

For production-grade distributed locking, however, you need to consider ownership, expiry, failures, and Redis topology rather than treating a single command as a complete locking solution.


πŸ—οΈ Redis in a Real Node.js Architecture

A typical backend might look like:

                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                     β”‚   Client     β”‚
                     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                     β”‚ Load Balancerβ”‚
                     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                ↓                       ↓
         Node.js Server 1       Node.js Server 2
                β”‚                       β”‚
                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
                         Redis
                            ↓
                         Database
Enter fullscreen mode Exit fullscreen mode

Redis can handle:

  • Frequently accessed data
  • Sessions
  • Rate-limit counters
  • Temporary tokens
  • Distributed coordination
  • Real-time messaging

while the database remains the primary source of durable business data in many architectures.


🎯 Redis Interview Cheat Sheet

Before a Node.js backend interview, remember:

Redis
 ↓
In-memory data store
 ↓
Fast
 ↓
Cache
 ↓
TTL
 ↓
Cache Hit / Miss
 ↓
Cache-Aside
 ↓
Cache Invalidation
 ↓
Rate Limiting
 ↓
Sessions
 ↓
Atomic Operations
 ↓
Pub/Sub
 ↓
Streams
 ↓
RDB / AOF
 ↓
Eviction
 ↓
Cache Stampede
 ↓
Distributed Lock
Enter fullscreen mode Exit fullscreen mode

Questions you should be able to answer

1. Why is Redis fast?

Because it is designed around in-memory data access and efficient data structures.

2. Redis vs PostgreSQL?

Redis is commonly used for fast access, caching, sessions and transient/shared state; PostgreSQL is generally used for durable relational business data.

3. What is Cache-Aside?

Application checks Redis β†’ on miss queries DB β†’ stores result in Redis β†’ returns response.

4. How do you handle stale cache?

Invalidate or update the cache when the underlying database data changes.

5. Why Redis for rate limiting?

Fast shared storage plus atomic operations such as INCR.

6. RDB vs AOF?

RDB = snapshots.
AOF = append-only write log.

7. What happens if Redis goes down?

For cache use cases, the application should ideally fall back to the database where appropriate, with proper timeouts, error handling and monitoring.


πŸ’‘ Final Takeaway

Redis isn't just a "cache."

For a backend developer, think of Redis as a high-speed shared data layer that can solve several problems:

Caching       β†’ Reduce DB load
TTL           β†’ Automatically expire data
Rate limiting β†’ Control requests
Sessions      β†’ Share session state
Counters      β†’ Atomic increments
Pub/Sub       β†’ Lightweight messaging
Streams       β†’ Durable event processing
Locks         β†’ Distributed coordination
Persistence   β†’ RDB / AOF
Enter fullscreen mode Exit fullscreen mode

If you're preparing for a 2+ YOE Node.js interview, focus less on memorizing commands and more on being able to explain why Redis is used, where it fits in the architecture, cache invalidation, failure scenarios, and the trade-offs involved.


πŸ“š Further Reading

nodejs #redis #backend #javascript #webdevelopment #systemdesign #interview

Full CheatSheet