New to Rust? Grab our free Rust for Beginners eBook Get it free →
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.

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

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

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

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:

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();

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.




