Skip to main content

tanstack-ai-memory-redis

Use when wiring redis() from @tanstack/ai-memory/redis in production — covers client setup (ioredis or node-redis via fromNodeRedis), the storage model, client-side ranking limits, and troubleshooting.

Jump to install

Source facts

Repository
TanStack/ai
Last source activity
September 9, 2026 at 06:08
Detected SKILL.md language
English
Stars
3,117
Forks
330

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
tanstack-ai-memory-redis
description
Use when wiring redis() from @tanstack/ai-memory/redis in production — covers client setup (ioredis or node-redis via fromNodeRedis), the storage model, client-side ranking limits, and troubleshooting.
# Redis Memory Adapter Production-grade `recall`/`save` adapter backed by plain Redis (no vector index required). Ranks client-side (lexical + optional cosine + recency + importance). ## Setup Bring your own Redis client. `ioredis` wires in directly; `redis` (node-redis v4+) needs a small wrapper. ### Option A: `ioredis` ```ts import Redis from 'ioredis' import { memoryMiddleware } from '@tanstack/ai-memory' import { redis } from '@tanstack/ai-memory/redis' const client = new Redis(process.env.REDIS_URL ?? 'redis://localhost:6379') const memory = redis({ redis: client, prefix: 'myapp:memory' }) // Resolve scope per request from the server-validated session — never from req.body. function memoryFor(session: { userId: string; threadId: string }) { return memoryMiddleware({ adapter: memory, scope: { threadId: session.threadId, userId: session.userId }, }) } ``` ### Option B: `redis` (node-redis v4+) ```ts import { createClient } from 'redis' import { memoryMiddleware } from '@tanstack/ai-memory' import { redis, fromNodeRedis } from '@tanstack/ai-memory/redis' const client = createClient({ url: process.env.REDIS_URL }) await client.connect() const memory = redis({ redis: fromNodeRedis(client), prefix: 'myapp:memory', }) function memoryFor(session: { userId: string; threadId: string }) { return memoryMiddleware({ adapter: memory, scope: { threadId: session.threadId, userId: session.userId }, }) } ``` node-redis exposes a camelCase API (`sAdd`, `mGet`); `fromNodeRedis` translates it to the lowercase `RedisLike` shape. Passing a raw node-redis client without the wrapper throws `client.sadd is not a function`. `redis()` accepts the same `topK` / `minScore` / `kinds` / `embedder` / `extract` options as `inMemory()`. ## Storage model ```text {prefix}:record:{id} -> JSON record {prefix}:index:{tenantId or _}:{userId or _}:{threadId} -> Set<id> ``` `save` writes the record and adds it to the scope's index set; `recall` loads the set, scores, and renders. Scope values are escaped (`:`, `\`, and `_`) so a delimiter or the unset placeholder inside a dim can't collide two scopes. **Hard cut:** there is no dual-read of older index layouts. If you previously wrote under a different shape (e.g. without `tenantId`), reindex or wipe — old keys are orphaned. Always pass the same `tenantId`/`userId`/`threadId` on write and read: missing optional dims become `_`, so omit ≠ "match any". ## Ranking limits Ranking is client-side: `recall` loads every record for the scope into Node and scores it. Fine up to ~10k records per scope. Beyond that, write a vector-index-aware adapter against the same `recall`/`save` contract. ## Troubleshooting - **Records not visible across processes:** ensure every process uses the same `REDIS_URL` and `prefix`. - **Malformed JSON rows:** a row whose JSON won't parse is skipped on read and **left in place** (never deleted) — the signal is a one-time `console.warn` per bad id. Fix or delete the offending `{prefix}:record:{id}` key to remediate.
View on GitHub