Package Exports
- memcore
- memcore/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (memcore) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
memcore
Lock-free shared in-memory cache for Node.js — accessible across worker processes on the same machine. Uses POSIX shared memory, N-API, and atomic operations only. No Redis, no network, no locks.
Why memcore?
- No external services — Skip Redis, Memcached, or any daemon. One
npm installand you have a shared cache; no config, no ports, no network. - Sub-microsecond latency — Data lives in mmap’d shared memory. Gets and sets are in-process; no serialization or TCP round-trips.
- True cross-process sharing — Cluster workers share the same cache via POSIX shared memory. Ideal for session storage, rate limiting, and counters without a separate cache server.
- Lock-free design — No mutexes or spinlocks in the hot path. Atomic operations and careful memory ordering keep throughput high and latency predictable under contention.
- Predictable memory — Fixed size and capacity at init; no runtime allocations in the addon. Easier to reason about and tune for production.
- Small surface area — Simple API (
init,set,get,del,incr,stats, etc.). No connection pools, no retries, no client libraries to maintain. - Benchmarks — Single-process: ~1.2M set/s and ~1.5M get/s; p50 latency under 1 µs. Run
npm run benchmarkon your machine for real numbers (see Benchmarks below).
Use memcore when you need a fast, shared, in-memory cache for multiple Node.js workers on one machine and want to avoid external dependencies and network overhead.
Features
- Lock-free — No mutexes; atomic operations and explicit memory ordering only.
- Cross-process — Multiple Node.js workers (e.g.
cluster) share one cache via POSIX shared memory. - No external services — No daemons, no sockets; everything lives in shared memory.
- Ultra-low latency — In-process mmap access; typical get/set in sub-microsecond range.
- Fixed memory footprint — Size and capacity determined at init; no runtime allocations in the addon.
Installation
npm install memcoreSystem requirements
- Platform: Linux (primary), macOS (same POSIX APIs; Windows not supported).
- Node.js: 18 or higher.
- Build:
node-gyp(usually installed with npm). On Linux:build-essential, Python 3; on macOS: Xcode Command Line Tools.
The native addon is built automatically on npm install via node-gyp rebuild. The JavaScript API is written in TypeScript and provides type definitions (dist/index.d.ts) for consumers.
Build from source
If you need to rebuild the addon or recompile TypeScript (e.g. after changing Node version):
npm run build
# or separately:
npm run build:addon
npm run build:tsThe binary is produced at build/Release/memcore.node. TypeScript compiles to dist/.
Development & Testing
From the repo, install dependencies and build:
npm install
npm run buildThen run tests and examples:
| Command | Description |
|---|---|
npm test |
Stress test (1 worker, 5000 ops) |
npm run stress |
Stress test (default workers/ops) |
npm run stress:stability |
Long-running stability test (60s) |
npm run benchmark |
Throughput and latency benchmark |
npm run example |
Multi-worker cluster example |
Stress test options: --workers N, --ops N, --duration N, --stability, --shm NAME, --size N, --seed N.
Quick start
const cache = require('memcore');
cache.init('mycache', 8); // name, size in MB
cache.set('key', 'value'); // true
cache.get('key'); // 'value'
cache.del('key'); // true
cache.stats(); // { capacity, count, keyMaxBytes, valueMaxBytes }
cache.clear();TypeScript:
import * as cache from 'memcore';
cache.init('mycache', 8);
cache.set('key', 'value');
const value = cache.get('key'); // string | null
const s = cache.stats(); // { capacity, count, keyMaxBytes, valueMaxBytes }From the repo: npm run build then node dist/examples/quickstart.js. Multi-worker: npm run example or node dist/examples/cluster.js.
Multi-worker example
Using the Node.js cluster module so multiple workers share one cache:
const cluster = require('cluster');
const cache = require('memcore');
const SHM_NAME = 'myapp_cache';
const CACHE_SIZE_MB = 8;
if (cluster.isPrimary) {
cache.init(SHM_NAME, CACHE_SIZE_MB);
cache.set('greeting', 'Hello from primary');
cluster.fork();
cluster.fork();
} else {
cache.init(SHM_NAME, CACHE_SIZE_MB);
console.log(cache.get('greeting')); // 'Hello from primary'
cache.set('worker_' + cluster.worker.id, 'data');
}Run: npm run build then node dist/examples/cluster.js (from repo), or npm run example.
API reference
| Method | Signature | Description |
|---|---|---|
init |
init(name, sizeMB) |
Create or attach to POSIX shm segment. name becomes /name. Call once per process before any other call. |
set |
set(key, value [, ttlMs]) |
Insert or update. Returns true on success, false if table full or key/value too long. Optional ttlMs for TTL in milliseconds. |
get |
get(key) |
Returns string value or null if not found or expired. |
del |
del(key) |
Remove key. Returns true if removed, false if not found. |
clear |
clear() |
Set all slots to empty (visible to all processes). |
stats |
stats() |
Returns { capacity, count, keyMaxBytes, valueMaxBytes }. |
incr |
incr(key, delta) |
Atomic increment. Creates numeric slot if missing. Returns new value. |
decr |
decr(key, delta) |
Atomic decrement. Returns new value. |
close |
close() |
Release process-local mapping and fd. Safe to call multiple times; called on process exit by default. |
Constants: cache.KEY_MAX (64), cache.VALUE_MAX (256) — UTF-8 byte limits; keys up to 63 bytes, values up to 255 bytes. Longer strings cause set to return false or throw from the JS wrapper.
Benchmarks
Single-process throughput and latency (example run; your numbers will vary by CPU and load):
| Operation | Throughput (ops/s) | Latency (avg ms) |
|---|---|---|
| set | ~1,200,000 | ~0.0008 |
| get | ~1,500,000 | ~0.0007 |
Latency percentiles (μs), single process:
| p50 | p95 | p99 | |
|---|---|---|---|
| set | ~0.6 | ~1.2 | ~2 |
| get | ~0.5 | ~1.0 | ~1.5 |
Assumptions: Linux or macOS, single process or multi-worker on one machine, 16 MB cache, 100-byte values. Run npm run benchmark on your hardware for representative results.
Use cases
- High-frequency backends — Session or request metadata without network round-trips.
- Rate limiting — Atomic
incr/decracross workers. - Session storage — Shared session map for cluster workers.
- Queue metadata — Head/tail or counters in shared memory.
- Real-time systems — Low-latency state shared across processes.
Limitations
- Single machine only — POSIX shared memory is local to the host; no network.
- Fixed key/value sizes — Key max 63 bytes UTF-8, value max 255 bytes UTF-8; fixed at design time.
- No persistence — Segment is in RAM; process crash or reboot clears data.
- Linux / macOS — Developed on Linux; macOS uses same POSIX APIs. Windows is not supported (no POSIX shm).
Safety notes
- Lifecycle: Call
init(name, sizeMB)once per process. The segment persists until all processes unmap it and the segment is removed (e.g.shm_unlink). If a process dies after claiming a slot but before committing, that slot can remainRESERVEDuntilclear()or reinit. - Cleanup: The addon registers an
exithandler to callclose(). For long-running servers this releases the fd; the mapping is process-local. - Concurrency: Lock-free algorithms are used; multiple readers and writers are safe. No blocking except during initial init.
License
MIT