What is Redis?

Redis (REmote DIctionary Server) is an open-source, in-memory key-value data store. Let's break that down:

  • In-Memory: Unlike a traditional database like PostgreSQL or MySQL which primarily stores data on a disk (SSD/HDD), Redis keeps the entire dataset in RAM. This makes read and write operations incredibly fast, often taking less than a millisecond.
  • Key-Value Store: At its core, Redis is a dictionary. You store a piece of data (a value) and associate it with a unique identifier (a key). Values can be simple strings or more complex data structures like lists, sets, and hashes.
  • Data Structure Server: Because it natively supports these complex data types, you can use it for much more than just simple key-value storage.

Think of Redis as your application's short-term, lightning-fast memory, while your SQL database is its long-term, persistent storage.

Use Case 1: Caching

This is the most common use case for Redis. Imagine you have a popular blog post that is read thousands of times per minute. Querying your main database for this post every single time is inefficient and puts a huge load on the database. Caching is the solution.

The most common caching strategy is the cache-aside pattern. The logic is simple:

  1. Your application needs some data.
  2. It first checks the Redis cache to see if the data is there (Cache Hit).
  3. If it is, it returns the data from Redis immediately. Fast!
  4. If it's not there (Cache Miss), the application queries the primary database (the "source of truth").
  5. It then stores a copy of that data in the Redis cache with an expiration time (e.g., 5 minutes) before returning it. The next request for this data within 5 minutes will be a cache hit.

Code Snippet: Cache-Aside in a Node.js/Express App

Let's implement this for an endpoint that fetches a user's profile. You'll need express and the redis npm package.

JavaScript


import express from 'express';
import { createClient } from 'redis';

// --- Setup ---
const app = express();
const db = { // A fake database for our example
  users: {
    '101': { name: 'Alice', bio: 'Software Engineer' },
    '102': { name: 'Bob', bio: 'Product Manager' },
  }
};
const redisClient = createClient(); // Connects to redis://localhost:6379 by default
await redisClient.connect();

// --- The Route ---
app.get('/users/:id', async (req, res) => {
  const { id } = req.params;
  const cacheKey = `user:${id}`;

  try {
    // 1. Check Redis cache first
    const cachedUser = await redisClient.get(cacheKey);

    if (cachedUser) {
      // 2. CACHE HIT: Data found in cache
      console.log(`CACHE HIT for ${cacheKey}`);
      return res.json(JSON.parse(cachedUser));
    }

    // 3. CACHE MISS: Data not in cache, query the database
    console.log(`CACHE MISS for ${cacheKey}. Querying database...`);
    const user = db.users[id];

    if (!user) {
      return res.status(404).json({ message: 'User not found' });
    }

    // 4. Store the result in Redis with a 60-second expiration (EX)
    await redisClient.set(cacheKey, JSON.stringify(user), { EX: 60 });
    
    return res.json(user);

  } catch (error) {
    console.error(error);
    return res.status(500).json({ message: 'Server error' });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

Use Case 2: Session Management

When a user logs in, the server creates a "session" to remember them across multiple requests. If you only have one server, you could store this session data in its memory. But what happens when you scale to multiple servers? If a user's request hits a different server, their session won't be found.

Redis provides a perfect solution: a centralized session store. All your server instances can read and write session data to the same Redis database, making your application stateless and easily scalable. Libraries like connect-redis make this simple to integrate with Express.

Use Case 3: Pub/Sub (Publish/Subscribe)

Pub/Sub is a messaging pattern where senders (publishers) send messages to channels, and receivers (subscribers) listen to those channels to receive messages in real-time. The publisher and subscriber don't know about each other; they only know about the channel.

This is great for real-time notifications, chat applications, or triggering actions across different microservices.

Code Snippet: Simple Redis Pub/Sub

You would run these two scripts in separate terminals.

publisher.js:

JavaScript


import { createClient } from 'redis';
const client = createClient();
await client.connect();

async function publishMessage() {
  const message = `Hello from the publisher! Time: ${new Date().toLocaleTimeString()}`;
  // Publish the message to the 'news' channel
  await client.publish('news', message);
  console.log(`Published: ${message}`);
}

setInterval(publishMessage, 3000); // Publish a new message every 3 seconds

subscriber.js:

JavaScript


import { createClient } from 'redis';
const client = createClient();
await client.connect();

// Subscribe to the 'news' channel
await client.subscribe('news', (message, channel) => {
  console.log(`Received message from channel '${channel}': ${message}`);
});

console.log("Subscriber is listening to the 'news' channel...");

When you run both, you'll see the subscriber printing messages in real-time as the publisher sends them.