DEV Community

klority
klority

Posted on Originally published at Medium

Stop Running Docker Just for Redis: Meet redis-local

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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    │
└─────────────────────┴──────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

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 EVALSHA to manage locks, delayed jobs, and token renewal. Mocks crash immediately with ERR 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)    |                  |
     |              +---------------------------+                  |
     +-------------------------------------------------------------+
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

  1. The script is compiled and cached in the Wasm sandbox.
  2. Every redis.call(...) inside Lua invokes our in-memory JavaScript command engine synchronously.
  3. 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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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 });
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

When NOT to Use redis-local

A quick disclaimer:

redis-local is 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!

What do you currently use for running Redis locally? Have you tried moving away from Docker Desktop? Drop your thoughts below! 👇

Top comments (0)