npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

redis-test-server

v0.0.3

Published

A lightweight, in-memory, Redis-compatible server for cheap, isolated automated tests.

Readme

redis-test-server

A lightweight, in-memory, Redis-compatible server for Node.js, built for one job: making automated tests cheap and isolated. It speaks the real Redis protocol (RESP2 and RESP3), so ordinary Redis clients — in particular the current node-redis — connect and work without any special adapter.

It is not a production Redis. There is no persistence, replication, clustering, or eviction. It reproduces the Redis interface and the observable semantics your tests depend on, and nothing more.

Why

Spinning up a real Redis (or a container) for every test file is slow and awkward to isolate. redis-test-server starts in well under a millisecond, listens on an ephemeral port, and tears down with no leaked timers or handles — so you can run many completely independent instances in parallel.

Install

npm install --save-dev redis-test-server

Node.js 20+ is required. There are no runtime dependencies.

Usage

import { RedisTestServer } from 'redis-test-server';
import { createClient } from 'redis';

const server = await RedisTestServer.create();  // ephemeral port by default
console.log(server.url);                        // redis://127.0.0.1:<port>

const client = createClient({ url: server.url });
await client.connect();

await client.set('hello', 'world');
console.log(await client.get('hello'));         // 'world'

await client.quit();
await server.close();                           // closes sockets, clears data

RedisTestServer.create() accepts:

| Option | Default | Meaning | | --- | --- | --- | | port | 0 | 0 lets the OS pick a free port; read it back from server.port. | | host | 127.0.0.1 | Bind address. | | databases | 16 | Number of logical databases (as in real Redis). | | now | Date.now | Injectable clock (ms) — handy for deterministic TTL tests. | | activeExpiration | false | Enable a background expiry sweep. Off by default so an idle server keeps no timers alive. |

Test isolation

The server is cheap enough that the simplest strategy — one server per test file — is usually the right one:

import { test, before, after } from 'node:test';
import { createClient } from 'redis';
import { RedisTestServer } from 'redis-test-server';

let server, client;
before(async () => {
  server = await RedisTestServer.create();
  client = createClient({ url: server.url });
  await client.connect();
});
after(async () => {
  await client.quit();
  await server.close();
});

If you want to share one TCP server across many tests, each test can use its own logical database via SELECT, or call FLUSHDB between tests. All of these keep standard Redis behavior; nothing nonstandard is added to normal commands.

Supported commands

See docs/compatibility.md for the full matrix. Current coverage:

  • Connection: HELLO, PING, ECHO, QUIT, SELECT, CLIENT (SETNAME/GETNAME/SETINFO/ID), COMMAND (stub), DBSIZE, FLUSHDB, FLUSHALL
  • Keys: DEL, UNLINK, EXISTS, TYPE, EXPIRE, PEXPIRE, EXPIREAT, PEXPIREAT, TTL, PTTL, PERSIST
  • Strings: GET, GETEX, SET (EX/PX/EXAT/PXAT/NX/XX/GET/KEEPTTL), SETNX, GETSET, MGET, MSET, INCR, INCRBY, DECR, DECRBY, APPEND, STRLEN
  • Hashes: HSET, HGET, HMGET, HGETALL, HDEL, HEXISTS, HLEN, HKEYS, HVALS, HINCRBY
  • Sets: SADD, SREM, SISMEMBER, SMEMBERS, SCARD
  • Lists: LPUSH, RPUSH, LPUSHX, RPUSHX, LPOP, RPOP, LLEN, LINDEX, LRANGE
  • Transactions: MULTI, EXEC, DISCARD, WATCH, UNWATCH

Unknown commands return a standard Redis unknown command error.

Architecture

TCP socket (node:net)
  → streaming RESP decoder   (src/resp/decoder.js)
  → command dispatcher       (src/commands/registry.js)
  → command implementations  (src/commands/*.js)
  → in-memory database       (src/database.js, src/value.js)
  → protocol-aware encoder   (src/resp/encoder.js)
  → TCP socket

Protocol handling, storage, command semantics, and server lifecycle are kept separate. Storage uses plain Map/Array/Buffer; keys and values are binary-safe. Expiration is lazy (checked on access) with an optional single background sweep — never one timer per key.

How compatibility is verified

Redis itself is the behavioral oracle. Two test tiers:

  • Fast suite (npm test) — protocol (RESP2 + RESP3 over a raw socket), command, integration, and lifecycle tests. The integration tests use the current node-redis (v6) client over both RESP2 and RESP3. Runs in well under a second and needs no Docker or real Redis.
  • Differential suite (npm run test:compat) — launches an official redis:7.2 container and runs identical command scenarios against both real Redis and this server, asserting the results (including error messages, null behavior, TTL semantics, and wrong-type errors) match exactly. Requires Docker; skips gracefully when it is unavailable.

The reference Redis source (tag 7.2.16) is the authority for observable behavior. It is not committed here; fetch it on demand with npm run fetch:redis (the differential suite does this automatically). See docs/redis-source-notes.md for how specific Redis source functions map to this implementation.

Benchmarks

npm run bench measures the use case that matters: create/destroy cost, concurrent creation, 1,000 logical databases, memory per database, throughput, and an empirical comparison of isolation strategies. On a typical dev machine a create+destroy cycle is ~1 ms and an empty logical database costs ~400 bytes. See docs/benchmarks.md for numbers and the strategy recommendation.

Scope

Deliberately out of scope: RDB/AOF persistence, replication, Redis Cluster, Sentinel, ACLs, modules, Lua/EVAL scripting, Streams, Pub/Sub, blocking commands, and eviction policies. The core is structured so more commands can be added without reworking it.

License

MIT for this project. The Redis reference source (fetched on demand into reference/redis/, not distributed here) is licensed under its own terms (BSD 3-Clause); see reference/redis/COPYING after fetching, or THIRD_PARTY_NOTICES.md.