Skip to content

fatal10110/js-redis-server

Repository files navigation

js-redis-server

CI npm version npm downloads License: MIT Node.js Version

In-memory Redis-compatible server implementation in JavaScript. Useful for testing and development without requiring a real Redis instance.

Table of Contents

Features

  • RESP2 and RESP3 protocols - Per-session version negotiation via HELLO
  • Standalone and Cluster modes - Run a single server or a full cluster
  • Lua scripting support - Execute Redis Lua scripts via WebAssembly
  • No external dependencies - Pure JavaScript, no Redis installation needed
  • TypeScript support - Ships with full type definitions

Installation

npm install js-redis-server

Quick Start

As a Library

import {
  RedisServerState,
  createRedisCommandExecutor,
  Resp2Server,
} from 'js-redis-server'

const logger = {
  info: console.log,
  error: console.error,
  debug: console.debug,
}

const state = new RedisServerState()
const executor = createRedisCommandExecutor()
const server = new Resp2Server({ server: state, executor, logger })

await server.listen(6379)
console.log(`Redis server listening at ${server.getAddress()}`)

// Cleanup
await server.close()

As a CLI

# Run a single server on default port 6379
npx js-redis-server

# Run on a specific port
npx js-redis-server --port 6380

# Run a cluster with 3 masters
npx js-redis-server --cluster --masters 3

# Run a cluster with replicas
npx js-redis-server --cluster --masters 3 --slaves 1

CLI Options

Modes:
  --single               Run a single Redis server (default)
  --cluster              Run a Redis cluster
  --mode <single|cluster>

Single server options:
  --port <number>        Port to listen on (default 6379)

Cluster options:
  --masters <number>     Number of masters (default 3)
  --slaves <number>      Number of replicas per master (default 0)
  --base-port <number>   Starting port for cluster nodes (default 30000)

General:
  -d, --debug            Enable debug logging
  -h, --help             Show help

Cluster Mode

import { buildRedisCluster } from 'js-redis-server'

const logger = {
  info: console.log,
  error: console.error,
  debug: console.debug,
}

const cluster = buildRedisCluster({
  masters: 3,
  replicasPerMaster: 1,
  basePort: 30000,
  logger,
})

await cluster.listen()

// Get all node addresses
console.log(cluster.nodes.map(n => `${n.host}:${n.port}`))

// Cleanup
await cluster.close()

Connecting Clients

You can connect to js-redis-server using any standard Redis client.

Protocol Version (RESP2 / RESP3)

Each connection starts on RESP2 and can switch to RESP3 by sending HELLO 3 (handled per-session, no server restart needed). Clients that support RESP3 negotiate this automatically:

import { createClient } from 'redis'

// node-redis negotiates RESP3 via the `RESP` option
const client = createClient({
  url: 'redis://127.0.0.1:6379',
  RESP: 3,
})
await client.connect()

Connecting with ioredis

import Redis from 'ioredis'

// Single Node
const redis = new Redis(6379, '127.0.0.1')

// Cluster Node
const cluster = new Redis.Cluster([
  { host: '127.0.0.1', port: 30000 },
  { host: '127.0.0.1', port: 30001 },
  { host: '127.0.0.1', port: 30002 },
])

Connecting with node-redis

import { createClient, createCluster } from 'redis'

// Single Node
const client = createClient({
  url: 'redis://127.0.0.1:6379'
})
await client.connect()

// Cluster Node
const cluster = createCluster({
  rootNodes: [
    { url: 'redis://127.0.0.1:30000' },
    { url: 'redis://127.0.0.1:30001' },
    { url: 'redis://127.0.0.1:30002' },
  ]
})
await cluster.connect()

Using in Unit Tests

Since js-redis-server starts instantly, it is perfect for isolated integration testing in Node.js test frameworks (like Mocha, Jest, or Node's test runner):

import { test, before, after } from 'node:test'
import assert from 'node:assert'
import Redis from 'ioredis'
import { RedisServerState, createRedisCommandExecutor, Resp2Server } from 'js-redis-server'

let server: Resp2Server
let client: Redis

before(async () => {
  const state = new RedisServerState()
  const executor = createRedisCommandExecutor()
  server = new Resp2Server({ server: state, executor })
  
  await server.listen(6379)
  client = new Redis(6379, '127.0.0.1')
})

after(async () => {
  await client.quit()
  await server.close()
})

test('basic set/get operations', async () => {
  await client.set('foo', 'bar')
  const val = await client.get('foo')
  assert.strictEqual(val, 'bar')
})

API Reference

Resp2Server

Creates a TCP server running the RESP2 protocol.

new Resp2Server(options: Resp2ServerOptions)

Options (Resp2ServerOptions):

Parameter Type Required Description
server RedisServerState Yes The database server state containing database instances.
executor CommandExecutor Yes The command executor handling pipeline and execution policies.
logger Pick<Logger, 'error'> No Optional logger for error logging.
encoder RespEncodeOptions No Custom RESP protocol encoding options.

RedisServerState

Holds the database and keyspace state for the server.

new RedisServerState(options?: RedisServerStateOptions)

Options (RedisServerStateOptions):

Parameter Type Default Description
databaseCount number 1 Number of databases to initialize.
clusterTopology RedisClusterTopology undefined Optional cluster topology for slot routing.
pubsubBroker RedisPubSubBroker undefined Optional broker for pub/sub operations.
scriptCache RedisScriptCache undefined Optional cache for Lua scripts.

buildRedisCluster

Utility function to build and configure a complete Redis cluster in-memory.

buildRedisCluster(options: RedisClusterOptions): RedisCluster

Options (RedisClusterOptions):

Parameter Type Default Description
masters number Required Number of master nodes in the cluster.
replicasPerMaster number 0 Replicas per master node.
basePort number Required Base port range. If 0, random OS ports are assigned.
host string '127.0.0.1' Host address to bind to.
databasesPerNode number 1 Number of databases per cluster node.
logger Pick<Logger, 'error'> undefined Optional logger.

Requirements

  • Node.js >= 24

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Lint and format
npm run lint
npm run format

# Run integration tests (mock backend)
npm run test:integration:mock

# Run integration tests (real Redis)
# Requires a Redis cluster — start one with docker-compose.test.yml first:
#   docker compose -f docker-compose.test.yml up -d --wait
npm run test:integration:real

# Run all tests
npm run test:all

CI runs four jobs on every push and pull request: lint + format check, unit tests, mock-backend integration tests, and real-backend integration tests against a Redis cluster spun up via docker-compose.test.yml.

Further Documentation

For more details on the architecture, testing infrastructure, and command support, see:

Contributing

Contributions are welcome! Please read the contributing guidelines before submitting a pull request.

License

MIT - see LICENSE for details.

About

Mini in-memory redis server useful for client agnostic mocks

Resources

License

Contributing

Stars

Watchers

Forks

Contributors