If you're building any kind of backend or full-stack application in 2026, you've probably had this exact experience:
You clone a repository. You run npm install. You fire up npm run dev.
And boom — your terminal explodes:
[ioredis] Unhandled error event: Error: connect ECONNREFUSED 127.0.0.1:6379
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1606:16)
Right. The project uses Redis for session storage, caching, or background queues.
So you heave a heavy sigh and launch Docker Desktop.
Your laptop fans immediately ramp up like a jet engine preparing for takeoff. Activity Monitor shows Docker's virtual machine claiming 2.5GB to 4.2GB of RAM. On Windows, you cross your fingers that WSL2 networking doesn't flake out. On locked-down corporate laptops, you might not even have root/admin permissions to install or run hypervisors.
All of that massive computing overhead... just to read and write a few string keys on 127.0.0.1.
We asked ourselves:
Why does running a lightweight in-memory key-value store on a developer machine require an entire virtualized Linux operating system?
Today, we're sharing redis-local — a completely free, open-source, zero-dependency Redis replacement that boots in under 500 milliseconds, uses just ~28MB of memory, and runs directly on Node.js using WebAssembly.
No Docker. No WSL2. No C++ build tools (node-gyp).
You don't even need to install it. Just open a terminal and run:
npx redis-local
And your local Redis server is live and accepting connections on port 6379.
The 3 Ways Local Redis Usually Sucks
Before writing our own implementation, we looked at every existing option. Every single one had annoying friction:
┌────────────────────────────────────────────────────────────────────────┐
│ The Local Redis Dilemma │
├─────────────────────┬──────────────────────────────────────────────────┤
│ Approach │ The Pain Point │
├─────────────────────┼──────────────────────────────────────────────────┤
│ 🐳 Docker Desktop │ 2.5GB–4.5GB RAM, 30s boot, battery drain │
│ 🐧 WSL2 / Hyper-V │ Port forwarding quirks, VM overhead │
│ 🧪 In-Memory Mocks │ Crashes on BullMQ, Lua EVALSHA, and Streams │
│ 📦 Legacy MSOpenTech│ Abandoned in 2016 (Redis 3.2), critical CVEs │
│ ⚡ redis-local │ <500ms boot, ~28MB RAM, BullMQ/Lua, 0-Docker │
└─────────────────────┴──────────────────────────────────────────────────┘
1. The Docker Tax
Docker is great for production staging, but for quick local iteration, it's brutal:
- Memory Hog: Allocates 2GB–4GB of system RAM whether you're using it or not.
- Boot Delay: 15 to 45 seconds to spin up daemons and containers.
- Corporate IT Blockers: Many enterprise devs aren't granted admin rights to run Docker daemons or hypervisors.
2. In-Memory Mock Libraries (ioredis-mock, redis-mock)
Mocks work fine for basic unit tests doing SET and GET. But the moment your application does anything modern:
-
BullMQ Dies: BullMQ relies on atomic Lua scripts via
EVALSHAto manage locks, delayed jobs, and token renewal. Mocks crash immediately withERR unknown command 'EVALSHA'. - Multi-Process Inability: In-memory mocks live inside a single Node.js process. If you run your API server in one terminal and a background worker in another, they can't share state.
3. Archived Windows Binaries (MSOpenTech)
The native Windows port was abandoned in 2016 at Redis 3.2. Modern commands, Streams (XADD, XREAD), and Redis 5+ queue semantics don't exist, and it's filled with unpatched security vulnerabilities.
How redis-local Works
redis-local implements the official RESP (REdis Serialization Protocol) over standard Node.js TCP sockets. Any client in any language (ioredis, Python's redis-py, go-redis, or redis-cli) connects to it seamlessly:
+-----------------------------------+
| Your Application (Port 6379) |
| ioredis / redis-py / go-redis |
+-----------------+-----------------+
|
| TCP (RESP Protocol)
v
+-------------------------------------------------------------+
| redis-local |
| |
| +--------------------+ +----------------------------+ |
| | Pure JS RESP Parser| | WebAssembly Lua 5.4 VM | |
| | & Command Router | | (wasmoon sandbox) | |
| +---------+----------+ +--------------+-------------+ |
| | | |
| +---------------+---------------+ |
| v |
| +---------------------------+ |
| | In-Memory Data Structures | |
| | Strings, Hashes, Lists, | |
| | Sorted Sets, Pub/Sub, | |
| | Streams, Key Expirations | |
| +-------------+-------------+ |
| | |
| v |
| +---------------------------+ |
| | Optional JSON Snapshot | |
| | (--save redis-dump) | |
| +---------------------------+ |
+-------------------------------------------------------------+
The Hard Part: Lua Scripting in Pure JS
The real challenge in building a Redis replacement is Lua.
Queue engines like BullMQ run multi-step Lua scripts with atomic guarantees:
-- Sample snippet from BullMQ's moveToActive script
local jobId = redis.call('RPOPLPUSH', KEYS[1], KEYS[2])
if jobId then
redis.call('HSET', KEYS[3], 'processedBy', ARGV[1])
return jobId
end
return nil
If your local server cannot execute Lua atomically with a bi-directional redis.call() bridge, BullMQ refuses to run.
To solve this without requiring native C++ compilers (no node-gyp, no Python, no Visual Studio build tools), we embedded wasmoon, a WebAssembly compilation of Lua 5.4.
When your app sends EVAL or EVALSHA:
- The script is compiled and cached in the Wasm sandbox.
- Every
redis.call(...)inside Lua invokes our in-memory JavaScript command engine synchronously. - The result is serialized back through RESP to your application.
Comparison Matrix
| Feature / Metric | ⚡ redis-local | 🐳 Docker Desktop | 🐧 WSL2 / Linux VM | 📦 Legacy MSOpenTech |
|---|---|---|---|---|
| Startup Speed | < 500 ms | 15 – 45 seconds | 5 – 15 seconds | 1 – 2 seconds |
| RAM Footprint | ~28 MB | 2.5 GB – 4.5 GB | 1.0 GB – 2.0 GB | ~30 MB |
| Installation Friction | Zero (npx) |
1.2 GB Installer | Distro + Hyper-V | Manual ZIP unzip |
| C++ Compilers Required | None (Pure Wasm) | None | None | Visual Studio 2017 |
| BullMQ & Lua Support | Full (Lua 5.4 Wasm) | Full | Full | ❌ Broken (v3.2) |
| Corporate Laptops | 100% (No Admin) | Restricted by IT | Hyper-V blocked | Unpatched CVEs |
| CI/CD Overhead | 0s (Headless Node) | 60-90s container pull | Unsupported | Windows Only |
3 Real-World Recipes
1. Instant 1-Liner
No global install required:
npx redis-local
Connect and test from another terminal:
redis-cli ping
# Output: PONG
redis-cli set dev "running smoothly"
# Output: OK
redis-cli get dev
# Output: "running smoothly"
2. BullMQ Job Queues (100% Supported)
Here's a working BullMQ script (worker.mjs):
import { Queue, Worker } from 'bullmq';
const connection = { host: '127.0.0.1', port: 6379 };
// 1. Create Queue
const queue = new Queue('emails', { connection });
// 2. Create Worker
const worker = new Worker('emails', async (job) => {
console.log(`[Worker] Sending email to ${job.data.email}`);
return { sent: true };
}, { connection });
worker.on('completed', (job) => {
console.log(`[Worker] Job ${job.id} completed!`);
});
// 3. Add Jobs (including delayed execution)
await queue.add('welcome', { email: 'dev@klority.com' }, { delay: 1000 });
Run node worker.mjs with redis-local active. Locks, repeatable jobs, and delayed queues work right out of the box.
3. Shave 60 Seconds off GitHub Actions CI
Instead of spinning up slow Docker-in-Docker service containers in your workflow, just run redis-local in the background:
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
# Spin up redis-local in background without Docker!
- name: Start Redis
run: npx redis-local --port 6379 &
- name: Run Tests
run: npm test
This simple change saves 45 to 90 seconds per test run, which adds up to hundreds of CI minutes saved every month.
Useful CLI Flags
# Custom port
npx redis-local --port 6380
# Auto-persist state to redis-dump.json upon shutdown
npx redis-local --save
# Custom snapshot path
npx redis-local --save ./my-cache.json
# Silent mode for test scripts
npx redis-local --silent
When NOT to Use redis-local
A quick disclaimer:
redis-localis strictly for local dev, automated testing, and CI pipelines.
Please don't run it in production! In production, you want high-availability clustering, failovers, and multi-region replication via AWS ElastiCache, Redis Enterprise, or GCP Memorystore.
redis-local is built specifically to make developer machines fast, light, and hassle-free.
Open Source & Links
redis-local is 100% open-source and maintained by the team at Klority (we build a unified engineering workspace that replaces Jira, Confluence, and TestRail).
If you find it useful, please consider giving us a star!
- ⭐️ GitHub: github.com/klority-io/redis-local
- 📦 npm: npmjs.com/package/redis-local
- 🌐 Interactive Tool Page: klority.com/tools/redis-local
What do you currently use for running Redis locally? Have you tried moving away from Docker Desktop? Drop your thoughts below! 👇
Top comments (0)