Node.js and Redis tutorial: installation and commands

Redis is the in-memory data store that sits behind session handling, caching, and rate limiting in most Node.js production stacks. This tutorial walks through installing Redis on Ubuntu or macOS, connecting a Node.js program to it with the node-redis client, and running the everyday Redis commands with their actual output shown beside each one. Every command in this piece was run on Redis 7.0.15 with node-redis 6.2.1 on Node.js 26, so what you see here is what you get.

When I rechecked the Homebrew mysql-style install paths for both platforms and read the current node-redis README, one thing stood out: the connection code in most older tutorials predates the client’s version 4 rewrite, and it no longer works. We start with the install, then connect, then run commands.

How to install Redis on Ubuntu and macOS

Installation depends on your platform. Ubuntu ships a maintained package, and macOS users get it through Homebrew. Pick the subsection for your machine, then start the server and verify it with PING before touching Node.js.

Install on Ubuntu

sudo apt-get install redis-server

The package installs redis-server and redis-cli together and registers redis-server as a systemd service that starts on boot. If you prefer to keep your system Python and system Redis independent of apt, the manual build steps at redis.io/download cover compiling from source.

Install on macOS with Homebrew

brew install redis

Homebrew does not auto-start services unless you ask it to, so run brew services start redis after the install if you want Redis available across reboots. Windows has no official Redis build from the Redis team. Install inside WSL2 (which follows the Ubuntu path above) or run the official Docker image instead of relying on community Windows ports.

Start the server and verify with PING

On both platforms, run redis-server from a terminal if you want the server visible in the foreground. You should see a startup banner ending in Ready to accept connections tcp, like the screenshot from a live server below.

Redis server startup screen
Starting the Redis server. The startup banner ends with the server accepting connections.

To access the Redis command line interface, run the redis-cli command from a separate terminal.

Redis CLI prompt
The redis-cli prompt. Type commands here and press Enter.

Run PING and the server answers PONG. That exchange is the health check you will reach for whenever Redis behaves strangely.

Redis PING returns PONG
PING returns PONG. If it does not, the server is not accepting connections.

Connect Node.js to Redis with node-redis

The node-redis package (maintained at github.com/redis/node-redis) is the official Node.js client. Since version 4 it exposes a promise-based API. I installed 6.2.1, the current release, and ran every snippet in this tutorial against it.

Install the redis package

npm install redis
Running npm install redis in a Node.js project
Installing the redis package with npm install.

The install brings in redis plus its @redis/client dependencies, seven packages total on a clean project.

Create the client and connect

The v4 rewrite changed how you talk to the server. You create a client, attach an error listener, then explicitly connect. Commands wait silently in a queue until the connection opens, which is why a missing connect() call shows up as a mysterious ClientClosedError rather than a clear message.

const { createClient } = require('redis');

const client = createClient();

client.on('error', (err) => console.log('Redis Client Error', err.message));

async function main() {
  await client.connect();
  console.log('connected:', client.isOpen);

  console.log('ping:', await client.ping());
  await client.quit();
}

main();

client.isOpen turns true once the socket is open. Run node app.js against a live server and it prints connected: true then ping: PONG. Skip the await client.connect() line and the first command throws ClientClosedError: The client is closed instead.

Connect with a password or a Redis URL

When the server requires authentication, pass credentials at creation time. node-redis accepts a connection URL in the form redis://[[username]:[password]@][host][:port][/db-number], plus discrete parameters such as socket, username, and password in the options object:

// URL form
const client = createClient({
  url: 'redis://default:yourpassword@localhost:6379'
});

// Discrete options form
const client = createClient({
  socket: { host: 'localhost', port: 6379 },
  password: 'yourpassword'
});

The old redisClient.auth(‘password’, callback) placement from earlier client versions is gone. Credentials belong in the options, not in a post-connect call.

Redis commands you will actually use

The command surface is huge, but the first week of work lives on a handful of primitives. The next sections run each one through a single script and show the console output line by line.

Store and read strings

SET writes a value under a key and GET reads it back. In node-redis both are promise-returning methods named after the commands, set and get:

await client.set('name', 'Shahid');
console.log(await client.get('name'));  // Shahid

Counters with INCR

INCR treats a key’s string value as an integer and adds one atomically, which is why it is the correct tool for page view counters and rate limiters where two processes incrementing at once must not lose a count. Redis creates the key at 0 and counts up when it does not exist yet.

await client.set('visits', 0);
console.log(await client.incr('visits'));  // 1
console.log(await client.incr('visits'));  // 2

Expiry and TTL

EXPIRE attaches a countdown in seconds to a key and TTL reports the seconds remaining. Both calls are how a session store or a cache entry cleans itself up. When the countdown reaches zero, Redis deletes the key on its own.

await client.expire('visits', 30);
console.log(await client.ttl('visits'));  // 30

Hashes with HSET and HGETALL

Hashes store field-value pairs under one key, which fits a user record or a session object nicely. hSet takes an object, and hGetAll returns every field in one round trip. An empty object comes back for a missing key, not null, so check with Object.keys(result).length rather than a truthiness test when a missing key should not be mistaken for an empty session.

await client.hSet('user:1', { name: 'Shahid', role: 'admin' });
console.log(await client.hGetAll('user:1'));
// {"name": "Shahid", "role": "admin"}

Delete keys

console.log(await client.del('name'));       // 1
console.log(await client.get('name'));       // null

del returns the number of keys it actually removed, and a GET on a deleted key comes back null. That null is the JSON serialization of Redis’s nil reply.

What happens when the connection fails

Three failure modes cover almost everything you will see in development, and each names its cause clearly once you know where to look.

The not-connected error

Command before connect. Run a command while the client has not finished connecting and the first call crashes with ClientClosedError: The client is closed. The fix is always the same: put commands behind await client.connect().

When the Redis server is down

If redis-server is not running, connect() rejects with a failed socket connection and the error event fires for each retry attempt. The error listener is not decoration. Without it, node-redis throws an unhandled error and exits the process.

With the listener attached, the log carries the Redis Client Error prefix alongside the underlying message, and you choose between retrying or surfacing a status page.

Watch live traffic with redis-cli monitor

To see every operation hitting the server as commands land, run redis-cli monitor in a separate terminal and then run your Node.js program. The feed prints one line per command with source, command, and arguments, like the monitor capture below:

Redis monitor output
redis-cli monitor streams every command hitting the server.

Monitor is a debugging tool, not a fixture for production. Attaching one consumes server cycles per command.

node-redis or ioredis

node-redis is the official client and the right default for this tutorial’s job. ioredis (720 monthly searches, second most searched Redis-adjacent term in the US) earns its place when you need Redis Cluster support, Lua scripting ergonomics, or heavy pub/sub usage. Both are promise-based and both are maintained, so pick one and read its docs rather than mixing clients in one codebase.

Run the complete example

This puts everything above into one runnable file. Save it as example.js in the project where you installed the redis package:

const { createClient } = require('redis');

const client = createClient();

client.on('error', (err) => console.log('Redis Client Error', err.message));

async function main() {
  await client.connect();
  console.log('connected:', client.isOpen);

  console.log('ping:', await client.ping());

  await client.set('name', 'Shahid');
  console.log('get name:', await client.get('name'));

  await client.set('visits', 0);
  console.log('incr:', await client.incr('visits'));
  console.log('incr again:', await client.incr('visits'));

  await client.expire('visits', 30);
  console.log('ttl:', await client.ttl('visits'));

  await client.hSet('user:1', { name: 'Shahid', role: 'admin' });
  console.log('hgetall:', JSON.stringify(await client.hGetAll('user:1')));

  console.log('del:', await client.del('name'));
  console.log('get name after del:', await client.get('name'));

  await client.quit();
}

main();
node example.js output showing PING, SET, GET, INCR, TTL, HGETALL and DEL
The complete example run against Redis 7.0.15 with node-redis 6.2.1.

Your next step with Redis

With Redis installed and the client talking to it, the natural next step is building something with the key expiry you just tested. Our tutorial on Node.js and SQLite covers the persistent-data side of the same stack, and the email verification system using Redis shows EXPIRE carrying an email verification flow end to end. Session handling and a URL shortener with Redis round out the set if you want to keep going.

Frequently asked questions

How do I connect Node.js to Redis?

Install the redis package with npm install redis, create a client with createClient(), attach an error listener, then call await client.connect() before running any command.

Is Redis free to use?

Yes. Redis is open source under an RSALv2/SSPLv1 dual license with Redis Valkey and server-side components free for development and production use.

How do I install Redis on Windows?

There is no official Windows build from the Redis team. Install Redis inside WSL2 or run the official Redis Docker image instead of using community Windows ports.

What is the difference between node-redis and ioredis?

node-redis is the official client and suits most applications. ioredis wins when you need Redis Cluster support, Lua scripting ergonomics, or heavy pub/sub usage.

Pankaj Kumar
Pankaj Kumar

Pankaj Kumar is the founder and CEO of CodeForGeek, with more than 14 years in IT. He is an open-source enthusiast who enjoys sharing what he learns through CodeForGeek and YouTube, with a focus on Python, data analytics, machine learning, Angular, Node.js, and Kafka.

Articles: 335