convex-chat
Authorization-aware direct and small-group chat primitives for Convex.

Live demo · Documentation
What it provides
- Conversations and chat-local memberships
- Revision-safe projection of host-managed membership access
- Ordered, idempotent text and attachment messages
- Realtime history and exact unread counts
- Replies, revision-safe edits, tombstones, and reactions
- Presence and typing state
- Provider-neutral attachment metadata
- Host-side helpers that keep identity derivation in your application
Install
pnpm add convex-chat convex
Register the component in convex/convex.config.ts:
import chat from "convex-chat/convex.config.js";
import { defineApp } from "convex/server";
const app = defineApp();
app.use(chat);
export default app;
Run npx convex dev to generate the component API. Your host functions can
then call components.chat directly or use the actor-scoped helpers:
import { exposeChatApi } from "convex-chat";
import { components } from "./_generated/api";
const api = exposeChatApi(components.chat, {
authenticate: async (ctx) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error("Unauthenticated");
return resolveChatActor(identity);
},
});
export const listConversations = api.listConversations;
export const listMessages = api.listMessages;
export const sendText = api.sendText;
Export the functions your client needs from that object, or use the same
pattern in custom queries and mutations. Conversation creation belongs in a
host-controlled mutation after the application has checked its relationship
and product-policy rules.
The host can also use the trusted getMemberAccess and setMemberAccess
component functions to project its policy to read_write, read_only, or
none. The setter requires the current membership revision. Do not expose
these privileged functions directly to clients.
Security boundary
The host application must authenticate every public caller and derive
scopeId and subjectId server-side. Never allow an untrusted client to choose
another user's subject ID. The component repeats chat-local membership checks
for actor operations even when the host wrapper has authenticated the caller.
Attachment bytes and storage credentials stay outside the component. The
host application can integrate Cloudflare R2, native Convex storage, S3, or
another provider without changing the durable chat model.
See the repository README,
supported contract,
presence guide,
attachment guide,
and security policy
for more detail.
Projects importing convex-chat/test should install compatible convex-test
and Vite versions as development dependencies. They are optional peers and are
not required by production consumers.
License
Apache-2.0