Databases & SQL/
Lesson

Now that you understand what Redis is, it's time to use it in real code. The official redis npm package gives you a clean async interface that maps almost one-to-one with the CLIWhat is cli?Short for Command Line Interface. A tool you use by typing commands in the terminal instead of clicking buttons. commands you learned in the previous lesson. Once you see the caching pattern in action, you'll want to add it everywhere.

Installing and connecting

Setup

Start by installing the package and creating a client. The client connects to Redis over TCP, so you give it a URL pointing to your Redis server.

npm install redis
import { createClient } from 'redis';

const client = createClient({
  url: 'redis://localhost:6379'  // default Redis port
});

client.on('error', (err) => {
  console.error('Redis connection error:', err);
});

await client.connect();

The error event listener is important. Without it, unhandled connection errors can crash your Node.js process entirely. Always register it before calling connect().

In production, your Redis URL will come from an environment variable like process.env.REDIS_URL. Never hardcode credentials or hostnames in source files.

Verifying the connection

After connecting, do a quick round-trip to confirm everything works:

await client.set('ping', 'pong');
const result = await client.get('ping');
console.log(result); // 'pong'
02

Basic read and write operations

Strings

The Node.js client method names match the Redis CLIWhat is cli?Short for Command Line Interface. A tool you use by typing commands in the terminal instead of clicking buttons. commands almost exactly: set, get, del, exists, expire.

// Store a string
await client.set('username', 'alice');

// Retrieve it
const name = await client.get('username');
console.log(name); // 'alice'

// Store with TTL (expires after 1 hour)
await client.set('session:xyz', 'data', { EX: 3600 });

// Delete
await client.del('username');

Storing objects

Redis strings can hold any text, so you can store JSONWhat is json?A text format for exchanging data between systems. It uses key-value pairs and arrays, and every programming language can read and write it.-serialized objects. You just need to serialize on write and parse on read.

const user = { id: 1, name: 'Alice', role: 'admin' };

await client.set('user:1', JSON.stringify(user), { EX: 600 });

const raw = await client.get('user:1');
const parsed = JSON.parse(raw);
console.log(parsed.name); // 'Alice'
JSON.parse(null) returns null in JavaScript, so if a key doesn't exist, client.get() returns null and JSON.parse(null) gives you null. That's actually safe, just check for it before using the value.
03

The cache-aside pattern

How it works

Cache-aside (also called "lazy loadingWhat is lazy loading?Deferring the loading of a resource like an image or component until the moment it's actually needed, speeding up the initial page load.") is the most common caching pattern. The idea is simple: check Redis first, and only hit the database if the data isn't cached yet.

Request comes in
    |
    v
Check Redis --> HIT  --> Return cached data (fast)
    |
    MISS
    |
    v
Query database --> Store result in Redis --> Return data
ScenarioRedis called?Database called?Speed
Cache hitYesNoFast
Cache missYes (write)YesNormal
Key expiredYes (write)YesNormal

Implementation

Here's a complete cache-aside function you can drop into any Express route:

async function getCachedUser(id) {
  const cacheKey = `user:${id}`;

  // Step 1: check the cache
  const cached = await client.get(cacheKey);
  if (cached) {
    console.log('Cache hit');
    return JSON.parse(cached);
  }

  // Step 2: cache miss - query the database
  console.log('Cache miss, querying DB');
  const user = await db.users.findById(id);

  if (!user) return null;

  // Step 3: store in Redis for future requests
  await client.set(cacheKey, JSON.stringify(user), { EX: 3600 });

  return user;
}

Cache invalidationWhat is cache invalidation?Removing or updating cached data when the original data changes, so users never see outdated information.

When the underlying data changes, you need to remove or update the cached copy. Forgetting this is the most common caching bug, users see stale data.

async function updateUser(id, updates) {
  // Update the database
  await db.users.update(id, updates);

  // Invalidate the cache so the next read gets fresh data
  await client.del(`user:${id}`);
}
There's a saying in software
"There are only two hard things in computer science: cache invalidation and naming things." Stale caches cause real bugs. When in doubt, set a short TTL and let the cache expire naturally.
04

Closing the connection

In a long-running server process, you keep the Redis client alive for the lifetime of the process. In scripts or serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you. functions, disconnect when you're done.

// In a script
await client.disconnect();

// In an Express server
process.on('SIGTERM', async () => {
  await client.disconnect();
  process.exit(0);
});
05

Quick reference

Node.js methodRedis equivalentDescription
client.set(key, value)SET key valueStore a string
client.set(key, value, { EX: n })SETEX key n valueStore with TTL
client.get(key)GET keyRetrieve a string
client.del(key)DEL keyDelete a key
client.exists(key)EXISTS keyCheck existence
client.incr(key)INCR keyIncrement counter
client.expire(key, n)EXPIRE key nSet TTL on existing key
client.ttl(key)TTL keyGet remaining TTL
javascript
import { createClient } from 'redis';

async function redisDemo() {
  const client = createClient();
  await client.connect();

  // Simple string
  await client.set('framework', 'Express');
  const value = await client.get('framework');
  console.log(value); // 'Express'

  // Using Hashes (Objects)
  await client.hSet('user:42', {
    name: 'John',
    surname: 'Doe'
  });

  const user = await client.hGetAll('user:42');
  console.log(user); // { name: 'John', surname: 'Doe' }

  await client.disconnect();
}