Skip to content

vcms-io/solidis

Repository files navigation

Solidis

The fastest Redis client for Node.js.
Zero dependencies, 2x+ faster than ioredis, battle-tested in production.


npm coverage deps bundle RESP modules

Quick Start  ·  Features  ·  Configuration  ·  Architecture  ·  Extensions  ·  한국어


Bundle size comparison

Rocket
0 deps
zero dependencies
Package
383
commands
Test Tube
19K+
lines of tests
Feather
< 29KB
min bundle

Quick Start

npm install @vcms-io/solidis
import { SolidisFeaturedClient } from '@vcms-io/solidis/featured';

const client = new SolidisFeaturedClient({ host: '127.0.0.1', port: 6379 });

await client.set('key', 'value');
const value = await client.get('key');

Tip

Need a smaller bundle? Use SolidisClient with .extend() to import only the commands you use. Minimum bundle drops to < 29KB with tree-shaking.

  Tree-shakable client
import { SolidisClient } from '@vcms-io/solidis';
import { get } from '@vcms-io/solidis/command/get';
import { set } from '@vcms-io/solidis/command/set';

import type { SolidisClientExtensions } from '@vcms-io/solidis';

const extensions = { get, set } satisfies SolidisClientExtensions;
const client = new SolidisClient({ host: '127.0.0.1', port: 6379 }).extend(extensions);
  Transactions & Pipelines
// Transaction (MULTI/EXEC)
const tx = client.multi();
tx.set('key', 'value');
tx.incr('counter');
const results = await tx.exec();

// Pipeline (raw)
const results = await client.send([
  ['set', 'a', '1'],
  ['incr', 'counter'],
  ['get', 'a']
]);
  Pub/Sub
client.on('message', (channel, message) => {
  console.log(`${channel}: ${message}`);
});
await client.subscribe('events');

Bar Chart Benchmarks

High Voltage Solidis vs ioredis High Voltage

Generated on 2026-06-22 15:21:54 · linux x64 · Node.js v22.22.3

Up to 2.1x faster than ioredis! Rocket



15 / 15 benchmarks won · 74% average speed improvement · 111% peak speed improvement

100,000 iterations × 10,000 concurrency · 1 KB payload · 10 repeats

Benchmark Commands solidis ioredis Difference Performance
1st Place Medal Set Mutation SADD SISMEMBER SREM 1610ms 3398ms 2.1x FireFire ██████████
2nd Place Medal List Mutation LPUSH RPUSH LPOP RPOP LLEN 2475ms 4597ms 1.9x FireFire ████████░░
3rd Place Medal Set Read SADD SISMEMBER SMEMBERS 1703ms 3142ms 1.8x FireFire ████████░░
4. Sorted Set ZADD ZRANGE ZREM 1734ms 3182ms 1.8x FireFire ████████░░
5. Set SET 754ms 1367ms 1.8x FireFire ███████░░░
6. Expire SET EXPIRE TTL 1522ms 2751ms 1.8x FireFire ███████░░░
7. List Range LPUSH RPUSH LRANGE 2045ms 3692ms 1.8x FireFire ███████░░░
8. Hash Mutation HMSET HMGET HDEL 2052ms 3564ms 1.7x FireFire ███████░░░
9. Multi-Key MSET MGET 1475ms 2551ms 1.7x FireFire ███████░░░
10. Stream XADD XRANGE XLEN 1847ms 3189ms 1.7x FireFire ███████░░░
11. Non-Transaction SETPX GET 1348ms 2269ms 1.7x FireFire ██████░░░░
12. Pipeline Mixed SET INCR GET 1688ms 2738ms 1.6x FireFire ██████░░░░
13. Counter INCR DECR 1015ms 1599ms 1.6x Fire █████░░░░░
14. Hash Round-Trip HSET HGET HGETALL 1901ms 2827ms 1.5x Fire ████░░░░░░
15. Get Buffer GETBUFFER 624ms 928ms 1.5x Fire ████░░░░░░

Non Strictly Comparable Benchmarks

These benchmarks have library-specific behavior that prevents a strictly fair comparison.

Benchmark Commands solidis ioredis Difference Performance
16. Transaction SET EXPIRE GET 1397ms 6579ms 4.7x FireFire ██████████
17. Transaction Mixed SET GET 1400ms 4695ms 3.4x FireFire ██████████
18. Pub/Sub PUBLISH MESSAGE 754ms 2476ms 3.3x FireFire ██████████
19. Info / Config INFO CONFIGGET 1168ms 2042ms 1.7x FireFire ███████░░░

Ranked by performance gain of solidis over ioredis (baseline). Elapsed = median time across repeats.


Bar Chart Detailed Metrics

All metrics per library: operations/s, commands/s, median elapsed time, and spread (coefficient of variation).

Click to expand detailed metrics table
Benchmark Library ops/s cmds/s Elapsed Spread
Set Mutation: SADD SISMEMBER SREM
1 KB
solidis 62.1K 186.4K 1610ms ±8.9%
ioredis 29.4K 88.3K 3398ms ±5.1%
List Mutation: LPUSH RPUSH LPOP RPOP LLEN
1 KB
solidis 40.4K 202.0K 2475ms ±1.4%
ioredis 21.8K 108.8K 4597ms ±3.3%
Set Read: SADD SISMEMBER SMEMBERS
1 KB
solidis 58.7K 176.2K 1703ms ±1.2%
ioredis 31.8K 95.5K 3142ms ±1.2%
Sorted Set: ZADD ZRANGE ZREM
1 KB
solidis 57.7K 173.0K 1734ms ±2.0%
ioredis 31.4K 94.3K 3182ms ±1.4%
Set: SET
1 KB
solidis 132.6K 132.6K 754ms ±8.0%
ioredis 73.1K 73.1K 1367ms ±2.1%
Expire: SET EXPIRE TTL
1 KB
solidis 65.7K 197.1K 1522ms ±2.3%
ioredis 36.3K 109.0K 2751ms ±3.1%
List Range: LPUSH RPUSH LRANGE
1 KB
solidis 48.9K 146.7K 2045ms ±1.9%
ioredis 27.1K 81.3K 3692ms ±1.6%
Hash Mutation: HMSET HMGET HDEL
1 KB
solidis 48.7K 146.2K 2052ms ±3.1%
ioredis 28.1K 84.2K 3564ms ±1.0%
Multi-Key: MSET MGET
1 KB
solidis 67.8K 135.6K 1475ms ±3.3%
ioredis 39.2K 78.4K 2551ms ±1.8%
Stream: XADD XRANGE XLEN
1 KB
solidis 54.1K 162.4K 1847ms ±1.6%
ioredis 31.4K 94.1K 3189ms ±2.8%
Non-Transaction: SETPX GET
1 KB
solidis 74.2K 148.3K 1348ms ±8.4%
ioredis 44.1K 88.2K 2269ms ±1.2%
Pipeline Mixed: SET INCR GET
1 KB
solidis 59.2K 177.7K 1688ms ±9.3%
ioredis 36.5K 109.6K 2738ms ±2.4%
Counter: INCR DECR
1 KB
solidis 98.5K 197.0K 1015ms ±4.0%
ioredis 62.5K 125.0K 1599ms ±2.8%
Hash Round-Trip: HSET HGET HGETALL
1 KB
solidis 52.6K 157.8K 1901ms ±2.3%
ioredis 35.4K 106.1K 2827ms ±5.5%
Get Buffer: GETBUFFER
1 KB
solidis 160.1K 160.1K 624ms ±7.2%
ioredis 107.7K 107.7K 928ms ±2.2%

Gear Configuration

Click to expand benchmark configuration
Parameter Value
Mode autopipeline
Payload Sizes 1 KB
Iterations 100,000
Warmup 1,000
Clients 1
Concurrency / Client 10000
Total Concurrency 10000
Repeats 10
Cooldown 2500ms
Platform linux x64
Node.js v22.22.3
Date 2026-06-22 15:21:54

Open Book Methodology

  • Each benchmark is run in an isolated worker thread to prevent GC and JIT cross-contamination
  • Libraries are alternated between repeats to reduce ordering bias
  • The Redis server is flushed and settled between each benchmark case
  • Payloads use a deterministic pseudo-random pool shared by both libraries
  • Elapsed time is the median across all repeat samples
  • Spread is the coefficient of variation (σ / median × 100%)

Features

High Voltage Performance

  • setImmediate pipeline coalescing
  • Binary-safe RESP parser with owned buffers
  • Chunked socket writes with backpressure
  • Configurable event-loop yield points

Electric Plug Protocol

  • Full RESP2 + RESP3 wire-level implementation
  • All 17 RESP3 data types (Map, Set, Push, BigNumber, ...)
  • Automatic BigInt promotion for unsafe integers
  • Binary-safe, multi-byte character support

Shield Reliability

  • Auto-reconnect with configurable backoff
  • Auto-recovery: SELECT, Pub/Sub subscriptions
  • Per-pipeline command timeout
  • Ready check (waits for server loading)
  • Deterministic in-flight rejection on fault

Locked Security

  • TLS/SSL (rediss:// or explicit tls option)
  • ACL username/password authentication
  • Credential masking in debug output
  • maxBulkStringLength oversized reply guard

Bullseye Type Safety

  • TypeScript strict with per-command I/O types
  • Runtime reply guards (tryReplyToString, ...)
  • Structured error hierarchy + causal chain

Puzzle Piece Extensibility

  • .extend() for tree-shakable command composition
  • Custom commands with full client this binding
  • MULTI/EXEC proxy with banned-method enforcement

Configuration

Full options reference
const client = new SolidisClient({
  // Connection
  uri: 'redis://localhost:6379',
  host: '127.0.0.1',
  port: 6379,
  tls: { /* tls.ConnectionOptions */ },
  lazyConnect: false,

  // Auth
  authentication: { username: 'user', password: 'pass' },
  database: 0,

  // Protocol & Recovery
  clientName: 'solidis',
  protocol: 'RESP2',                      // 'RESP2' | 'RESP3'
  autoReconnect: true,
  enableReadyCheck: true,
  maxReadyCheckRetries: 100,
  readyCheckInterval: 100,
  maxConnectionRetries: 20,
  connectionRetryDelay: 100,
  autoRecovery: {
    database: true,
    subscribe: true,
    ssubscribe: true,
    psubscribe: true,
  },

  // Timeouts (ms)
  commandTimeout: 5000,
  connectionTimeout: 2000,
  socketWriteTimeout: 1000,

  // Performance
  maxCommandsPerPipeline: 300,
  maxProcessRepliesPerChunk: 4096,
  maxProcessReplyBytesPerChunk: 8_388_608,  // 8MB
  maxSocketWriteSizePerOnce: 65_536,        // 64KB
  rejectOnPartialPipelineError: false,

  // Parser
  parser: {
    buffer: { initial: 4_194_304, shiftThreshold: 2_097_152 },
    maxBulkStringLength: 536_870_912,       // 512MB
  },

  // Misc
  maxEventListenersForClient: 10_240,
  maxEventListenersForSocket: 10_240,
  debug: false,
  debugMaxEntries: 10_240,
});

Architecture

graph TD
  subgraph SolidisClient
    direction LR
    Conn[Connection<br/><sub>TCP · TLS · Reconnect</sub>]
    Req[Requester<br/><sub>Queue · Pipeline · Timeout</sub>]
    Parse[Parser<br/><sub>RESP2 · RESP3 · Binary-safe</sub>]
    PS[PubSub<br/><sub>Channel · Pattern · Shard</sub>]
    DM[Debug Memory<br/><sub>Ring buffer · Sanitized</sub>]
  end

  Conn -->|socket data| Req
  Req -->|raw bytes| Parse
  Req -->|push messages| PS
  DM -.->|injected| Conn
  DM -.->|injected| Req

  style Conn fill:#1a1a2e,stroke:#f5a623,color:#fff
  style Req fill:#1a1a2e,stroke:#f5a623,color:#fff
  style Parse fill:#1a1a2e,stroke:#f5a623,color:#fff
  style PS fill:#1a1a2e,stroke:#f5a623,color:#fff
  style DM fill:#16213e,stroke:#555,color:#aaa
Loading
sequenceDiagram
  participant App
  participant Client as SolidisClient
  participant Req as Requester
  participant Socket as TCP Socket

  App->>Client: await client.set('key', 'value')
  Client->>Req: enqueue command
  Note over Req: setImmediate batching
  Req->>Socket: write pipeline chunk
  Socket-->>Req: RESP reply bytes
  Req-->>Client: parsed reply
  Client-->>App: 'OK'
Loading

Events

client.on('connect', () => {});         // TCP connected
client.on('ready', () => {});           // Auth done, ready for commands
client.on('reconnected', () => {});     // Re-established after disconnect
client.on('end', () => {});             // Connection closed
client.on('error', (err) => {});        // Non-fatal error
client.on('message', (ch, msg) => {});  // Pub/Sub message
client.on('pmessage', (pat, ch, msg) => {});
client.on('smessage', (ch, msg) => {}); // Shard channel
client.on('debug', (entry) => {});      // Debug log entry

Error Handling

import { unwrapSolidisError, SolidisConnectionError, SolidisRequesterError } from '@vcms-io/solidis';

try {
  await client.set('key', 'value');
} catch (error) {
  const root = unwrapSolidisError(error); // full causal chain
}

Note

Every error thrown by Solidis is an instance of SolidisError. Use unwrapSolidisError() to traverse the full causal chain to the root cause.

Error Class When
SolidisConnectionError TCP/TLS connect failure, timeout, reset
SolidisRequesterError Command timeout, pipeline rejection, write failure
SolidisParserError Malformed RESP, oversized bulk string
SolidisPubSubError Subscription lifecycle error

Extensions

npm install @vcms-io/solidis-extensions
Extension Description
SpinLock Lightweight Redis-backed mutex (single instance)
RedLock Fault-tolerant distributed lock (Redlock algorithm)

Contributing

git clone https://github.com/vcms-io/solidis.git && cd solidis
npm install && npm run build && npm test

TypeScript strict · zero new deps · minimal bundle impact · SemVer

License

MIT · See LICENSE

About

The fastest Redis & Valkey client for Node.js. Zero dependencies, 2x+ faster than ioredis, battle-tested in production.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages