> convex-sdk
You are an expert in Convex, the reactive backend platform for TypeScript. You help developers build real-time applications with a built-in database, serverless functions, file storage, authentication, scheduled jobs, and automatic real-time sync to React/Next.js clients — replacing REST APIs, WebSocket servers, and database management with a single reactive backend that pushes updates to clients automatically.
curl "https://skillshub.wtf/TerminalSkills/skills/convex-sdk?format=md"Convex — Reactive Backend-as-a-Service
You are an expert in Convex, the reactive backend platform for TypeScript. You help developers build real-time applications with a built-in database, serverless functions, file storage, authentication, scheduled jobs, and automatic real-time sync to React/Next.js clients — replacing REST APIs, WebSocket servers, and database management with a single reactive backend that pushes updates to clients automatically.
Core Capabilities
Schema and Functions
// convex/schema.ts — Type-safe database schema
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
users: defineTable({
name: v.string(),
email: v.string(),
avatar: v.optional(v.string()),
role: v.union(v.literal("user"), v.literal("admin")),
tokenIdentifier: v.string(),
}).index("by_token", ["tokenIdentifier"])
.index("by_email", ["email"]),
messages: defineTable({
body: v.string(),
userId: v.id("users"),
channelId: v.id("channels"),
}).index("by_channel", ["channelId"]),
channels: defineTable({
name: v.string(),
description: v.optional(v.string()),
}),
});
// convex/messages.ts — Server functions
import { query, mutation, action } from "./_generated/server";
import { v } from "convex/values";
// Query: automatically reactive — clients re-render when data changes
export const list = query({
args: { channelId: v.id("channels"), limit: v.optional(v.number()) },
handler: async (ctx, args) => {
const messages = await ctx.db
.query("messages")
.withIndex("by_channel", (q) => q.eq("channelId", args.channelId))
.order("desc")
.take(args.limit ?? 50);
// Enrich with user data
return Promise.all(
messages.map(async (msg) => {
const user = await ctx.db.get(msg.userId);
return { ...msg, author: user?.name ?? "Unknown" };
}),
);
},
});
// Mutation: transactional write
export const send = mutation({
args: { body: v.string(), channelId: v.id("channels") },
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error("Not authenticated");
const user = await ctx.db
.query("users")
.withIndex("by_token", (q) => q.eq("tokenIdentifier", identity.tokenIdentifier))
.unique();
return ctx.db.insert("messages", {
body: args.body,
userId: user!._id,
channelId: args.channelId,
});
// All clients subscribed to `list` query automatically get the new message!
},
});
// Action: call external APIs (not transactional)
export const summarizeChannel = action({
args: { channelId: v.id("channels") },
handler: async (ctx, args) => {
const messages = await ctx.runQuery(api.messages.list, {
channelId: args.channelId,
limit: 100,
});
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
body: JSON.stringify({
model: "gpt-4o-mini",
messages: [{ role: "user", content: `Summarize: ${messages.map(m => m.body).join("\n")}` }],
}),
});
const data = await response.json();
return data.choices[0].message.content;
},
});
React Client
import { useQuery, useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
function Chat({ channelId }: { channelId: string }) {
// Automatically re-renders when messages change (any user sends a message)
const messages = useQuery(api.messages.list, { channelId });
const sendMessage = useMutation(api.messages.send);
const [input, setInput] = useState("");
return (
<div>
{messages?.map((msg) => (
<div key={msg._id}>
<strong>{msg.author}</strong>: {msg.body}
</div>
))}
<form onSubmit={(e) => {
e.preventDefault();
sendMessage({ body: input, channelId });
setInput("");
}}>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button type="submit">Send</button>
</form>
</div>
);
}
Installation
npm create convex@latest
npx convex dev # Local development with hot reload
npx convex deploy # Production deployment
Best Practices
- Queries are reactive —
useQueryauto-subscribes to data changes; no manual refetch, polling, or WebSocket setup - Mutations are transactional — Database writes in mutations are ACID; no partial updates on failure
- Actions for external calls — Use actions (not mutations) for API calls, file uploads; mutations must be deterministic
- Indexes for performance — Define indexes in schema for query patterns; Convex enforces indexed queries only
- Type safety end-to-end — Schema → functions → client all type-checked; change schema, TypeScript catches issues
- Scheduled functions — Use
ctx.scheduler.runAfter()for delayed tasks;crons.tsfor recurring jobs - File storage — Use
ctx.storage.store()for file uploads; generates signed URLs, handles CDN automatically - Auth integration — Built-in support for Clerk, Auth0, custom JWT;
ctx.auth.getUserIdentity()in any function
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.