--- title: "Convex" sidebarTitle: "Convex" description: "Add persistent memory to Convex apps with Supermemory" icon: "database" --- Convex apps don't have built-in memory for AI. Supermemory fixes that. You get a memory layer that stores conversations, builds user profiles, and gives your AI context about who it's talking to. ## What you can do - Store user interactions and retrieve them in future sessions - Build automatic user profiles from conversations - Search memories to give your AI relevant context - Keep everything in your Convex database for full visibility ## Setup Install the packages: ```bash npm install supermemory convex ``` For the AI chat example, also install the AI SDK packages: ```bash npm install @supermemory/tools @ai-sdk/openai ai ``` Set up your environment variable in Convex: ```bash npx convex env set SUPERMEMORY_API_KEY your-supermemory-api-key ``` Get your Supermemory API key from [console.supermemory.ai](https://console.supermemory.ai). ## Basic integration Create simple helper functions for each Supermemory operation: ```typescript // convex/memory.ts import { action } from "./_generated/server"; import { v } from "convex/values"; import Supermemory from "supermemory"; const memory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY }); // Get user profile and relevant memories export const getProfile = action({ args: { userId: v.string(), query: v.optional(v.string()) }, handler: async (ctx, { userId, query }) => { return await memory.profile({ containerTag: userId, q: query, }); }, }); // Add a memory export const addMemory = action({ args: { userId: v.string(), content: v.string() }, handler: async (ctx, { userId, content }) => { return await memory.add({ content, containerTag: userId, }); }, }); // Search memories export const searchMemories = action({ args: { userId: v.string(), query: v.string(), limit: v.optional(v.number()) }, handler: async (ctx, { userId, query, limit }) => { return await memory.search.memories({ q: query, containerTag: userId, searchMode: "hybrid", limit: limit ?? 10, }); }, }); ``` --- ## Example: AI chat with memory A chat endpoint using the Supermemory AI SDK middleware. It automatically injects context and saves memories. ```typescript // convex/chat.ts import { action } from "./_generated/server"; import { v } from "convex/values"; import { generateText } from "ai"; import { openai } from "@ai-sdk/openai"; import { withSupermemory } from "@supermemory/tools/ai-sdk"; export const chat = action({ args: { userId: v.string(), message: v.string() }, handler: async (ctx, { userId, message }) => { // Wrap the model - automatically injects context and saves memories const model = withSupermemory(openai("gpt-4o-mini"), { containerTag: userId, customId: `convex-chat-${userId}`, mode: "full", addMemory: "always", }); const { text } = await generateText({ model, system: "You are a helpful assistant.", prompt: message, }); return text; }, }); ``` --- ## Storing memories in Convex tables Keep a local copy of memories in your Convex database for full visibility: ```typescript // convex/schema.ts import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ memories: defineTable({ userId: v.string(), content: v.string(), createdAt: v.number(), }).index("by_user", ["userId"]), }); ``` ```typescript // convex/memory.ts import { action, mutation, query } from "./_generated/server"; import { api } from "./_generated/api"; import { v } from "convex/values"; import Supermemory from "supermemory"; const memory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY }); // Store in Convex export const storeMemory = mutation({ args: { userId: v.string(), content: v.string() }, handler: async (ctx, { userId, content }) => { return await ctx.db.insert("memories", { userId, content, createdAt: Date.now(), }); }, }); // Add memory to both Supermemory and Convex export const addMemory = action({ args: { userId: v.string(), content: v.string() }, handler: async (ctx, { userId, content }) => { // Add to Supermemory await memory.add({ content, containerTag: userId }); // Store in Convex // Note: in production, handle partial failures — if the Convex mutation // fails after the Supermemory write succeeds, the two stores will be out of sync. await ctx.runMutation(api.memory.storeMemory, { userId, content }); }, }); // List memories from Convex export const listMemories = query({ args: { userId: v.string() }, handler: async (ctx, { userId }) => { return await ctx.db .query("memories") .withIndex("by_user", q => q.eq("userId", userId)) .order("desc") .take(50); }, }); ``` --- ## Related docs How automatic profiling works Filtering and search modes Memory middleware for Next.js Memory for LangChain apps