@vcms-io/solidis
v0.3.1
Published
The fastest Redis client for Node.js. Zero dependencies, 2x+ faster than ioredis, battle-tested in production.
Readme
Quick Start
npm install @vcms-io/solidisimport { 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
SolidisClientwith.extend()to import only the commands you use. Minimum bundle drops to < 29KB with tree-shaking.
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);// 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']
]);client.on('message', (channel, message) => {
console.log(`${channel}: ${message}`);
});
await client.subscribe('events');Benchmarks
Solidis vs ioredis
Generated on 2026-06-20 11:21:19 · linux x64 · Node.js v22.22.3
Up to 2.1x faster than ioredis!
15 / 15 benchmarks won · 72% average speed improvement · 106% peak speed improvement
100,000 iterations × 10,000 concurrency · 1 KB payload · 10 repeats
| | Benchmark | Commands | solidis | ioredis | Difference | Performance |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------ | :-----------------------------------------------------------------------------------------------------: | :--------: | :-----: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------- |
| | Set Mutation | SADD SISMEMBER SREM | 1651ms | 3396ms | 2.1x | ██████████ |
| | List Range | LPUSH RPUSH LRANGE | 1860ms | 3623ms | 1.9x | █████████░ |
| | Multi-Key | MSET MGET | 1623ms | 3045ms | 1.9x | ████████░░ |
| 4. | List Mutation | LPUSH RPUSH LPOP RPOP LLEN | 2615ms | 4844ms | 1.9x | ████████░░ |
| 5. | Set | SET | 754ms | 1352ms | 1.8x | ████████░░ |
| 6. | Set Read | SADD SISMEMBER SMEMBERS | 1842ms | 3267ms | 1.8x | ███████░░░ |
| 7. | Hash Mutation | HMSET HMGET HDEL | 1933ms | 3414ms | 1.8x | ███████░░░ |
| 8. | Sorted Set | ZADD ZRANGE ZREM | 1559ms | 2673ms | 1.7x | ███████░░░ |
| 9. | Expire | SET EXPIRE TTL | 1478ms | 2530ms | 1.7x | ███████░░░ |
| 10. | Non-Transaction | SETPX GET | 1227ms | 2051ms | 1.7x | ██████░░░░ |
| 11. | Stream | XADD XRANGE XLEN | 1986ms | 3216ms | 1.6x | ██████░░░░ |
| 12. | Hash Round-Trip | HSET HGET HGETALL | 1829ms | 2749ms | 1.5x | █████░░░░░ |
| 13. | Counter | INCR DECR | 988ms | 1481ms | 1.5x | █████░░░░░ |
| 14. | Pipeline Mixed | SET INCR GET | 1710ms | 2562ms | 1.5x | █████░░░░░ |
| 15. | Get Buffer | GETBUFFER | 649ms | 960ms | 1.5x | █████░░░░░ |
Non Strictly Comparable Benchmarks
These benchmarks have library-specific behavior that prevents a strictly fair comparison.
| | Benchmark | Commands | solidis | ioredis | Difference | Performance |
| --: | :-------------------- | :-------------------------------------------------------------------: | :-----: | :-----: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------- |
| 16. | Pub/Sub | PUBLISH MESSAGE | 717ms | 2679ms | 3.7x | ██████████ |
| 17. | Transaction | SET EXPIRE GET | 1285ms | 4760ms | 3.7x | ██████████ |
| 18. | Transaction Mixed | SET GET | 1708ms | 6079ms | 3.6x | ██████████ |
| 19. | Info / Config | INFO CONFIGGET | 1073ms | 1993ms | 1.9x | ████████░░ |
Ranked by performance gain of solidis over ioredis (baseline). Elapsed = median time across repeats.
Detailed Metrics
All metrics per library: operations/s, commands/s, median elapsed time, and spread (coefficient of variation).
| Benchmark | Library | ops/s | cmds/s | Elapsed | Spread | | :--------------------------------------------------------------------------------------------------------------------------------------------- | :---------- | -----: | -----: | ------: | -----: | | Set Mutation: SADD SISMEMBER SREM1 KB | solidis | 60.6K | 181.7K | 1651ms | ±2.8% | | | ioredis | 29.4K | 88.3K | 3396ms | ±3.0% | | List Range: LPUSH RPUSH LRANGE1 KB | solidis | 53.8K | 161.3K | 1860ms | ±3.7% | | | ioredis | 27.6K | 82.8K | 3623ms | ±0.8% | | Multi-Key: MSET MGET1 KB | solidis | 61.6K | 123.2K | 1623ms | ±2.8% | | | ioredis | 32.8K | 65.7K | 3045ms | ±2.6% | | List Mutation: LPUSH RPUSH LPOP RPOP LLEN1 KB | solidis | 38.2K | 191.2K | 2615ms | ±2.6% | | | ioredis | 20.6K | 103.2K | 4844ms | ±2.4% | | Set: SET1 KB | solidis | 132.7K | 132.7K | 754ms | ±9.2% | | | ioredis | 74.0K | 74.0K | 1352ms | ±1.9% | | Set Read: SADD SISMEMBER SMEMBERS1 KB | solidis | 54.3K | 162.9K | 1842ms | ±3.6% | | | ioredis | 30.6K | 91.8K | 3267ms | ±2.1% | | Hash Mutation: HMSET HMGET HDEL1 KB | solidis | 51.7K | 155.2K | 1933ms | ±3.3% | | | ioredis | 29.3K | 87.9K | 3414ms | ±1.6% | | Sorted Set: ZADD ZRANGE ZREM1 KB | solidis | 64.2K | 192.5K | 1559ms | ±4.0% | | | ioredis | 37.4K | 112.2K | 2673ms | ±0.8% | | Expire: SET EXPIRE TTL1 KB | solidis | 67.7K | 203.0K | 1478ms | ±5.9% | | | ioredis | 39.5K | 118.6K | 2530ms | ±1.4% | | Non-Transaction: SETPX GET1 KB | solidis | 81.5K | 163.0K | 1227ms | ±2.7% | | | ioredis | 48.7K | 97.5K | 2051ms | ±1.3% | | Stream: XADD XRANGE XLEN1 KB | solidis | 50.4K | 151.1K | 1986ms | ±3.5% | | | ioredis | 31.1K | 93.3K | 3216ms | ±3.2% | | Hash Round-Trip: HSET HGET HGETALL1 KB | solidis | 54.7K | 164.0K | 1829ms | ±8.1% | | | ioredis | 36.4K | 109.1K | 2749ms | ±1.4% | | Counter: INCR DECR1 KB | solidis | 101.2K | 202.4K | 988ms | ±2.1% | | | ioredis | 67.5K | 135.0K | 1481ms | ±1.2% | | Pipeline Mixed: SET INCR GET1 KB | solidis | 58.5K | 175.4K | 1710ms | ±1.1% | | | ioredis | 39.0K | 117.1K | 2562ms | ±1.4% | | Get Buffer: GETBUFFER1 KB | solidis | 154.2K | 154.2K | 649ms | ±4.1% | | | ioredis | 104.2K | 104.2K | 960ms | ±1.8% |
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-20 11:21:19 |
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
Performance
setImmediatepipeline coalescing- Binary-safe RESP parser with owned buffers
- Chunked socket writes with backpressure
- Configurable event-loop yield points
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
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
Security
- TLS/SSL (
rediss://or explicittlsoption) - ACL username/password authentication
- Credential masking in debug output
maxBulkStringLengthoversized reply guard
Type Safety
- TypeScript
strictwith per-command I/O types - Runtime reply guards (
tryReplyToString, ...) - Structured error hierarchy + causal chain
Extensibility
.extend()for tree-shakable command composition- Custom commands with full client
thisbinding - MULTI/EXEC proxy with banned-method enforcement
Configuration
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:#aaasequenceDiagram
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'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 entryError 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. UseunwrapSolidisError()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 testTypeScript strict · zero new deps · minimal bundle impact · SemVer
License
MIT · See LICENSE
