Skip to Content
Jumentix DocsPackages@jumentix/key-value-storagekey-value-storage usage

@jumentix/key-value-storage — usage guide

Responsibility in context

  • Stack layer: persistence / infrastructure adapter
  • Owns: key/value port + InMemory/Redis adapters for shared state
  • Used with: @jumentix/mutex-service (locks on top of KV), backend composition
  • Not responsible for: document/SQL repositories, IndexedDB offline (Cana), HTTP SDKs

What it is

@jumentix/key-value-storage is the shared key/value port for caches, feature flags, session blobs, and mutex backends across Jumentix services. Every adapter implements the same IKeyValueStorageClient contract: connect, get, set, del, and disconnect.

Why it exists

Junior teams should not re-implement Redis wiring, in-memory test doubles, and response wrapping in every app. One port lets you start with InMemory in the browser and unit tests, then swap to Redis in Node servers via environment configuration — without changing call sites.

Prerequisites

  • Runtime: browser (InMemory only) or Node/Bun (InMemory or Redis).
  • For Redis: a running Redis instance and the redis peer dependency installed in the consuming app.
  • Prior reading: Getting started.
  • Environment (Redis): JUMENTIX_KEYVALUESTORAGE_DRIVER=redis plus Redis connection settings your deployment documents.

Glossary

TermMeaning
PortIKeyValueStorageClient — the interface every adapter implements.
AdapterA concrete client (InMemoryKeyValueStorageClient, RedisKeyValueStorageClient).
ServiceResponseWrapper { result?, error? } returned by every method — check error before using result.
PrefixKeys are stored as {prefix}:{keyName}; default prefix comes from JUMENTIX_KV_KEY_PREFIX or jumentix__.
DriverValue of JUMENTIX_KEYVALUESTORAGE_DRIVER passed to compileKeyValueStorageClient.
ConnectedBoolean flag set by connect(); adapters expect connect() before reads/writes in server code.

Steps

1. Install (< 5 minutes)

bun add @jumentix/key-value-storage

For Redis in Node, also install the Redis client your deployment uses (see package README for the supported version).

2. First success — in-memory get/set (< 10 minutes)

import { InMemoryKeyValueStorageClient } from '@jumentix/key-value-storage';

const client = InMemoryKeyValueStorageClient.compile();
await client.connect();

const write = await client.set('greeting', 'hello jumentix');
if (write.error) throw write.error;

const read = await client.get('greeting');
console.log(read.result); // 'hello jumentix'

await client.del('greeting');
await client.disconnect();

Verify success: read.result === 'hello jumentix' and no error field.

3. Core workflow — compile by environment

Use the factory when the driver should follow deployment config:

import { compileKeyValueStorageClient } from '@jumentix/key-value-storage';

// JUMENTIX_KEYVALUESTORAGE_DRIVER=inmemory | redis (default: redis)
const client = compileKeyValueStorageClient();
await client.connect();
Driver valueAdapterEnvironment
inmemory, in-memory, memoryInMemoryBrowser demos, unit tests
(default / redis)RedisNode servers

4. Core workflow — error-safe reads

Never assume result is defined — always branch on error:

async function readFlag(client, key: string, fallback = false) {
  const { result, error } = await client.get(key);
  if (error) throw error;
  return result ?? fallback;
}

5. Core workflow — pair with mutex-service

Mutex locks are KV keys under a configurable prefix. Create one shared KV client and pass it to MutexService.compile (see mutex-service usage guide).

6. Full surface — API map

ExportRole
IKeyValueStorageClientType of every adapter
InMemoryKeyValueStorageClient.compile()Singleton in-memory Map
RedisKeyValueStorageClient.compile()Redis-backed client (Node)
compileKeyValueStorageClient(driver?)Env-driven factory
ServiceResponseStandard { result, error } helper
BaseKeyValueStorageClientShared prefix/connect logic for custom adapters

Try it in the docs playground

In-memory key/value

Cache UI preferences for the Task list with the same service-result shape used by package adapters.

const client = api.createInMemory();
await client.connect();

await client.set('ui:selected-category', {
  id: 'work',
  name: 'Work',
  visibleTaskIds: ['task-1', 'task-3']
});
await client.set('ui:last-sort', 'priority-desc');

const selectedCategory = await client.get('ui:selected-category');
const lastSort = await client.get('ui:last-sort');
await client.del('ui:last-sort');
const deletedSort = await client.get('ui:last-sort');
await client.disconnect();

return {
  selectedCategory: selectedCategory.result,
  lastSort: lastSort.result,
  deletedSort: deletedSort.result
};

The playground stub exposes a simplified API for demos:

const client = api.createInMemory();
await client.set('greeting', 'hello jumentix');
const value = await client.get('greeting');

In real apps, use InMemoryKeyValueStorageClient.compile() and handle ServiceResponse as shown above.

Common errors

SymptomCauseFixVerify success
result is undefined but no errorKey never set or was deletedCall set first; confirm key spellingget returns expected value
Redis connection refusedRedis not running or wrong host/portStart Redis; check env varsconnect() returns without error
Wrong value under load testsSingleton InMemory client reusedCall InMemoryKeyValueStorageClient fresh per test suite or reset keysIsolated keys per test
Keys collide between appsSame prefix on shared RedisSet JUMENTIX_KV_KEY_PREFIX per serviceKeys namespaced in Redis CLI
connected stays falseSkipped connect()Await connect() before I/Oclient.connected === true

Junior checklist (“I can …”)

  • Install the package and run an in-memory set / get / del cycle.
  • Explain why every method returns ServiceResponse instead of throwing.
  • Choose InMemory vs Redis for a given environment and justify the choice.
  • Use compileKeyValueStorageClient with the correct driver env var.
  • Read a value safely with a fallback when the key is missing.
  • Describe how mutex-service builds on top of this port.

Next step

Add coordinated access with mutex-service, then continue the persistence journey from Getting started.