CtrlK
BlogDocsLog inGet started
Tessl Logo

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.

80

Quality

100%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

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

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)
const memory = redis({ redis: client, prefix: 'myapp:memory' })

memoryMiddleware({ adapter: memory, scope })

Option B: redis (node-redis v4+)

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',
})

memoryMiddleware({ adapter: memory, scope })

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

{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.
Repository
TanStack/ai
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.