Memory Module Guide
Store, retrieve, and manage memories with db.user(id) — the complete reference.
Applies to: @retaindb/sdk
The db.user(userId) interface is how you interact with a user's memory. Everything in this guide applies to both user-level and session-scoped operations.
import { RetainDB } from "@retaindb/sdk";
const db = new RetainDB({ apiKey: process.env.RETAINDB_KEY });Set RETAINDB_KEY once in your environment. No project setup required.
The full turn (recommended)
runTurn is the recommended starting point. It handles everything:
const { response, context } = await db.user(userId).runTurn({
messages,
generate: (ctx) => openai.chat.completions.create({
model: "gpt-4o",
messages: ctx.messages, // memories already injected
}),
});Use manual methods below when you need explicit control over what gets stored or retrieved.
Storing memories
Single fact or preference
await db.user(userId).remember("Prefers concise, bullet-point responses");Conversation dump (auto-extraction)
Pass the full message array — RetainDB extracts facts, preferences, and events automatically:
await db.user(userId).remember([
{ role: "user", content: "I work at Acme as a senior engineer" },
{ role: "assistant", content: "Got it! What are you working on?" },
{ role: "user", content: "Trying to reduce our API latency below 100ms" },
]);Scoped to a session
await db.user(userId).session(sessionId).remember("User asked about billing issue");Retrieving context
const { context, raw } = await db.user(userId).getContext("How should I respond?");
// context — formatted string ready for a system prompt
// raw — full search response with scores and metadataControl how many results come back:
const { context } = await db.user(userId).getContext("query", 10); // topK = 10Forgetting a memory
await db.user(userId).forget(memoryId);Memory types
Memories are automatically classified. You can also specify the type when storing manually:
| Type | What it captures | Example |
|---|---|---|
factual | Stable facts about the user | "Works at Acme Corp" |
preference | Communication style, tool choices | "Prefers bullet points" |
event | Things that happened at a point in time | "Deployed to production on March 15" |
relationship | Connections between people or entities | "Reports to Jordan" |
opinion | Stated views or assessments | "Thinks Tailwind is overrated" |
goal | Objectives being worked toward | "Trying to reduce latency below 100ms" |
instruction | Explicit directives for future behavior | "Always verify security before shipping" |
What ctx contains in runTurn
interface TurnContext {
context: string; // formatted memory string
messages: Message[]; // original messages + memory injected as system message
}If there are no memories yet, context is an empty string and messages is passed through unchanged.
Automatic learning
Every runTurn call stores the conversation after generating the response. This is non-blocking — it never delays your response. Over time, the memory store grows richer with every interaction, and getContext results improve automatically.
Error handling
try {
await db.user(userId).remember("Some fact");
} catch (error) {
if (error.code === "RATE_LIMITED") {
// Back off and retry
}
}Next step
Was this page helpful?
Your feedback helps us prioritize docs improvements weekly.