User and Session Scoping
Use db.user(id) and db.user(id).session(id) to scope all operations without repeating identifiers on every call.
Applies to: @retaindb/sdk
db.user(userId) creates a scoped handle for one user. All operations on that handle automatically use the right user identifier — you never repeat it.
The pattern
import { RetainDB } from "@retaindb/sdk";
const db = new RetainDB({ apiKey: process.env.RETAINDB_KEY });
// Everything is scoped to this user
const user = db.user("user-123");
await user.remember("Prefers bullet-point responses");
const { context } = await user.getContext("How to answer this user?");
await user.forget(memoryId);Adding a session
session() scopes memories to a specific conversation or run:
const session = db.user("user-123").session("chat-456");
// Scoped to user-123 AND chat-456
await session.remember("User is asking about the billing issue");
const { context } = await session.getContext("What is the current issue?");Use session() when:
- you want to debug a specific conversation
- you need memories isolated to one run
- you are tracking what happened in a single thread
Use just user() when:
- you want durable facts and preferences across all sessions
- you are storing long-term profile information
Full runTurn with session
const { response } = await db.user(userId).session(sessionId).runTurn({
messages,
generate: (ctx) => openai.chat.completions.create({
model: "gpt-4o",
messages: ctx.messages,
}),
});What runTurn does
- Extracts the last user message to use as the search query
- Retrieves relevant memories for the user (and session if scoped)
- Injects memories as a system message in
ctx.messages - Calls your
generatefunction with the enriched context - Stores the full conversation in the background (non-blocking)
The storage step is fire-and-forget — it never delays your response.
What getContext returns
const { context, raw } = await db.user(userId).getContext("query");
// context — formatted string, ready to inject as system prompt
// raw — full search response with scores, metadata, etc.Conversation dumps
Pass the full message array to remember and RetainDB extracts facts, preferences, and events automatically:
await db.user(userId).remember([
{ role: "user", content: "I work at Acme Corp as an engineer" },
{ role: "assistant", content: "Got it! How can I help you today?" },
{ role: "user", content: "I prefer short answers" },
]);Each turn is ingested and stored. Future getContext calls will surface the relevant parts.
One db per process
Create one RetainDB instance and reuse it. The internal write queue auto-drains on process exit — no manual flush needed in long-running servers.
// At the top of your app, once
export const db = new RetainDB({ apiKey: process.env.RETAINDB_KEY });
// In your handler
export async function handleMessage(userId: string, messages: Message[]) {
return db.user(userId).runTurn({
messages,
generate: (ctx) => llm.generate(ctx),
});
}Next step
Was this page helpful?
Your feedback helps us prioritize docs improvements weekly.