Skip to main content

Supabase Memory

SupabaseMemoryAdapter stores conversations in Supabase Postgres for applications already using Supabase.

Installation

npm install @voltagent/supabase @supabase/supabase-js

Database Setup

Run this SQL in your Supabase SQL Editor (adjusts table prefix if needed):

Schema SQL (click to expand)
-- Users table (for user-scoped working memory)
CREATE TABLE IF NOT EXISTS voltagent_memory_users (
id TEXT PRIMARY KEY,
metadata JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now()),
updated_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now())
);

-- Conversations table
CREATE TABLE IF NOT EXISTS voltagent_memory_conversations (
id TEXT PRIMARY KEY,
resource_id TEXT NOT NULL,
user_id TEXT NOT NULL,
title TEXT NOT NULL,
metadata JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now()),
updated_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now())
);

-- Messages table (UIMessage format)
CREATE TABLE IF NOT EXISTS voltagent_memory_messages (
conversation_id TEXT NOT NULL REFERENCES voltagent_memory_conversations(id) ON DELETE CASCADE,
message_id TEXT NOT NULL,
user_id TEXT NOT NULL,
role TEXT NOT NULL,
parts JSONB,
metadata JSONB,
format_version INTEGER DEFAULT 2,
created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now()),
PRIMARY KEY (conversation_id, message_id)
);

-- Workflow states (for suspension/resume)
CREATE TABLE IF NOT EXISTS voltagent_memory_workflow_states (
id TEXT PRIMARY KEY,
workflow_id TEXT NOT NULL,
workflow_name TEXT NOT NULL,
status TEXT NOT NULL,
suspension JSONB,
user_id TEXT,
conversation_id TEXT,
metadata JSONB,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);

-- Indexes
CREATE INDEX IF NOT EXISTS idx_voltagent_memory_conversations_user_id
ON voltagent_memory_conversations(user_id);

CREATE INDEX IF NOT EXISTS idx_voltagent_memory_conversations_resource_id
ON voltagent_memory_conversations(resource_id);

CREATE INDEX IF NOT EXISTS idx_voltagent_memory_messages_conversation_id
ON voltagent_memory_messages(conversation_id);

CREATE INDEX IF NOT EXISTS idx_voltagent_memory_messages_created_at
ON voltagent_memory_messages(created_at);

CREATE INDEX IF NOT EXISTS idx_voltagent_memory_workflow_states_workflow_id
ON voltagent_memory_workflow_states(workflow_id);

CREATE INDEX IF NOT EXISTS idx_voltagent_memory_workflow_states_status
ON voltagent_memory_workflow_states(status);

Credentials

Get your Supabase credentials:

  1. Go to Supabase Dashboard
  2. Open your project
  3. Go to Project SettingsAPI
  4. Copy Project URL and anon key

Store as environment variables: SUPABASE_URL and SUPABASE_KEY

Configuration

import { Agent, Memory } from "@voltagent/core";
import { SupabaseMemoryAdapter } from "@voltagent/supabase";
import { openai } from "@ai-sdk/openai";

// Using URL and key
const memory = new Memory({
storage: new SupabaseMemoryAdapter({
supabaseUrl: process.env.SUPABASE_URL!,
supabaseKey: process.env.SUPABASE_KEY!,
}),
});

// Using existing Supabase client
import { createClient } from "@supabase/supabase-js";

const supabaseClient = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_KEY!);

const memory = new Memory({
storage: new SupabaseMemoryAdapter({
client: supabaseClient,
}),
});

const agent = new Agent({
name: "Assistant",
model: openai("gpt-4o-mini"),
memory,
});

Configuration Options

OptionTypeDescription
supabaseUrlstringSupabase project URL (required if not using client)
supabaseKeystringSupabase anon key (required if not using client)
clientSupabaseClientExisting Supabase client (alternative to URL/key)
tableNamestringTable name prefix (default: voltagent_memory)
storageLimitnumberMax messages per conversation (default: 100)
debugbooleanEnable debug logging (default: false)
loggerLoggerOptional logger for structured logging

Note: Table prefix must match the SQL schema. If you use a custom tableName, update the SQL accordingly.

Features

  • Messages stored per userId and conversationId
  • Oldest messages pruned when storageLimit exceeded
  • Supports complex queries with filtering, pagination, and sorting

Working Memory

const memory = new Memory({
storage: new SupabaseMemoryAdapter({
supabaseUrl: process.env.SUPABASE_URL!,
supabaseKey: process.env.SUPABASE_KEY!,
}),
workingMemory: {
enabled: true,
scope: "conversation", // or "user"
},
});

See Working Memory.

import { Memory, AiSdkEmbeddingAdapter, InMemoryVectorAdapter } from "@voltagent/core";
import { SupabaseMemoryAdapter } from "@voltagent/supabase";
import { openai } from "@ai-sdk/openai";

const memory = new Memory({
storage: new SupabaseMemoryAdapter({
supabaseUrl: process.env.SUPABASE_URL!,
supabaseKey: process.env.SUPABASE_KEY!,
}),
embedding: new AiSdkEmbeddingAdapter(openai.embedding("text-embedding-3-small")),
vector: new InMemoryVectorAdapter(), // or pgvector adapter
});

See Semantic Search.

Production Setup

import { Agent, Memory } from "@voltagent/core";
import { SupabaseMemoryAdapter } from "@voltagent/supabase";
import { createClient } from "@supabase/supabase-js";
import { openai } from "@ai-sdk/openai";

const supabaseClient = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_KEY! // or service_role key for backend
);

const memory = new Memory({
storage: new SupabaseMemoryAdapter({
client: supabaseClient,
storageLimit: 200,
}),
});

const agent = new Agent({
name: "Assistant",
model: openai("gpt-4o-mini"),
memory,
});

Security:

  • Use anon key with Row Level Security (RLS) policies
  • Use service_role key only in secure backend environments
  • Store credentials in environment variables

Use cases:

  • Applications already using Supabase
  • Projects leveraging Supabase Auth, Realtime, or Storage
  • Environments requiring RLS policies

For production-ready zero-setup hosting, see Managed Memory.

Learn More

Table of Contents