IntegrationsUpdated 2026-03-18
Next.js Integration
Complete guide to integrating RetainDB into Next.js applications with App Router and Pages Router.
Applies to: Next.js 13+
Learn how to integrate RetainDB into your Next.js application for production use.
Installation
bash
npm install @retaindb/sdk
# or
pnpm add @retaindb/sdkApp Router (Next.js 13+)
Server-Side Only (Recommended)
For maximum security, always Use RetainDB on the server:
typescript
// app/api/chat/route.ts
import { RetainDBClient } from "@retaindb/sdk";
import { NextResponse } from "next/server";
const client = new RetainDBClient({
apiKey: process.env.RETAINDB_API_KEY!,
});
export async function POST(request: Request) {
const { userId, message } = await request.json();
// Search for relevant context
const context = await client.memory.search({
user_id: userId,
query: message,
top_k: 5,
});
// Generate response with your LLM
const response = await generateResponse(message, context.results);
// Store the interaction
await client.memory.add({
user_id: userId,
content: `User: ${message}\nAssistant: ${response}`,
memory_type: "event",
});
return NextResponse.json({ response });
}Client Component with API Route
Never expose API keys in client components:
typescript
// app/page.tsx (Client Component)
"use client";
import { useState } from "react";
export default function Chat() {
const [message, setMessage] = useState("");
const [response, setResponse] = useState("");
const sendMessage = async () => {
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: "user-123", message }),
});
const data = await res.json();
setResponse(data.response);
};
return (
<div>
<input value={message} onChange={(e) => setMessage(e.target.value)} />
<button onClick={sendMessage}>Send</button>
<p>{response}</p>
</div>
);
}RetainDB Hook
Create a reusable hook for your components:
typescript
// hooks/useRetainDB.ts
"use client";
import { useState, useCallback } from "react";
export function useRetainDB(userId: string) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const search = useCallback(async (query: string) => {
setLoading(true);
setError(null);
try {
const res = await fetch("/api/RetainDB/search", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId, query }),
});
if (!res.ok) throw new Error("Search failed");
return await res.json();
} catch (e) {
setError(e.message);
return null;
} finally {
setLoading(false);
}
}, [userId]);
const addMemory = useCallback(async (content: string, memoryType = "context") => {
setLoading(true);
setError(null);
try {
const res = await fetch("/api/RetainDB/add", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId, content, memoryType }),
});
if (!res.ok) throw new Error("Add failed");
return await res.json();
} catch (e) {
setError(e.message);
return null;
} finally {
setLoading(false);
}
}, [userId]);
return { search, addMemory, loading, error };
}Using the Hook
typescript
// app/components/ChatInput.tsx
"use client";
import { useRetainDB } from "@/hooks/useRetainDB";
export function ChatInput() {
const { search, addMemory, loading } = useRetainDB("user-123");
const handleSubmit = async (query: string) => {
// Search existing context
const context = await search(query);
// Add as new memory
await addMemory(query, "conversation");
console.log("Context found:", context);
};
return (
<button onClick={() => handleSubmit("Hello")} disabled={loading}>
{loading ? "Loading..." : "Send"}
</button>
);
}Environment Variables
bash
# .env.local
RETAINDB_API_KEY=rdb_your_key_hereServer Component Example
Use RetainDB directly in Server Components:
typescript
// app/dashboard/page.tsx
import { RetainDBClient } from "@retaindb/sdk";
const client = new RetainDBClient({
apiKey: process.env.RETAINDB_API_KEY!,
});
export default async function Dashboard() {
// Direct call - server-side only
const profile = await client.memory.getUserProfile({
user_id: "user-123",
});
return (
<div>
<h1>User Profile</h1>
<pre>{JSON.stringify(profile, null, 2)}</pre>
</div>
);
}Middleware for Auth
Protect your API routes:
typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
// Verify user session
const session = request.cookies.get("session");
if (!session) {
return NextResponse.redirect(new URL("/login", request.url));
}
// Add user ID to headers for API routes
const response = NextResponse.next();
response.headers.set("x-user-id", session.value);
return response;
}
export const config = {
matcher: ["/api/RetainDB/:path*"],
};Caching with Next.js
Cache RetainDB responses:
typescript
// app/api/chat/route.ts
export const dynamic = "force-dynamic";
export async function POST(request: Request) {
// Your RetainDB logic
const result = await client.memory.search({ ... });
// Response is not cached by default
return NextResponse.json(result);
}Or use unstable_cache:
typescript
import { unstable_cache } from "next/cache";
const getCachedContext = unstable_cache(
async (userId: string) => {
return await client.memory.search({
user_id: userId,
query: "preferences",
});
},
["user-context"],
{ revalidate: 300 } // 5 minutes
);Error Handling
typescript
// app/api/chat/route.ts
export async function POST(request: Request) {
try {
const result = await client.memory.search({ ... });
return NextResponse.json(result);
} catch (error) {
console.error(RetainDB error:),
@(## What RetainDB actually does, ## What RetainDB actually does),
@(Add RetainDB to your Claude Code, Add RetainDB to your Claude Code),
@(Add a RetainDB server entry, Add a RetainDB server entry),
@(call a simple RetainDB tool, call a simple RetainDB tool),
@(indexed RetainDB retrieval, indexed RetainDB retrieval),
@(want RetainDB to rank, want RetainDB to rank),
@(do not want RetainDB to scan, do not want RetainDB to scan),
@(For indexed RetainDB context, For indexed RetainDB context),
@(shipping RetainDB docs, shipping RetainDB docs),
@(discovering RetainDB, not, discovering RetainDB, not),
@(description: "Contributor-facing rules for shipping RetainDB docs, description: Contributor-facing rules for shipping RetainDB docs", error);
return NextResponse.json(
{ error: "Failed to get context" },
{ status: 500 }
);
}
}Next step
- SDK Quickstart — Full SDK guide
- Memory Module Guide — Memory operations
- API Reference — API details
Was this page helpful?
Your feedback helps us prioritize docs improvements weekly.