一键导入
convex
Build full-stack TypeScript apps with Convex — server functions, schema, auth, file storage, real-time, frontend integration, testing, deployment.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Build full-stack TypeScript apps with Convex — server functions, schema, auth, file storage, real-time, frontend integration, testing, deployment.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Create, verify, and improve AGENTS.md files. Minimal, focused, progressive disclosure. Fixes bloat, contradictions, stale info.
Audit and plan website optimisation for AI agents, AI search, LLM discoverability, llms.txt, structured data, and sitemaps.
Build distinctive, production-grade frontend interfaces (websites, components, dashboards, layouts) with polished UI design that avoids generic AI aesthetics.
Generate and validate Awesome list READMEs following sindresorhus/awesome standards.
Scaffold type-safe TypeScript projects with the Better-T-Stack CLI — new projects, features, or troubleshooting.
Exhaustive multi-agent code review with area-specific specialists, verified findings, and actionable remediation plans.
| name | convex |
| description | Build full-stack TypeScript apps with Convex — server functions, schema, auth, file storage, real-time, frontend integration, testing, deployment. |
This skill provides expert guidance for building applications with Convex - the full-stack reactive database platform.
When a user wants to start with Convex:
New project:
npm create convex@latest
npx convex dev
Add to existing project:
npm install convex
npx convex dev
Verify: Check dashboard at https://dashboard.convex.dev
Queries - Read-only, auto-reactive:
import { query } from "./_generated/server";
export const list = query({
args: { channelId: v.id("channels") },
handler: async ({ db }, { channelId }) => {
return await db.query("messages")
.withIndex("by_channel", (q) => q.eq("channel", channelId))
.collect();
}
});
Mutations - Write operations, transactions:
import { mutation } from "./_generated/server";
export const send = mutation({
args: { body: v.string(), channel: v.id("channels") },
handler: async ({ db }, { body, channel }) => {
await db.insert("messages", { body, channel, createdAt: Date.now() });
}
});
Actions - External API calls:
import { action } from "./_generated/server";
export const summarize = action({
args: { postId: v.id("posts") },
handler: async (ctx, { postId }) => {
const post = await ctx.runQuery(api.posts.get, { postId });
const summary = await fetchLLM(post);
await ctx.runMutation(api.posts.update, { postId, summary });
}
});
// CRUD
await db.insert("table", { field: value });
const doc = await db.get(id);
await db.patch(id, { field: newValue });
await db.delete(id);
// Query methods
.collect() // All results
.first() // First or null
.unique() // Exactly one (throws if not)
.paginate({ numItems: 50 }) // Pagination
File: convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
messages: defineTable({
body: v.string(),
author: v.id("users"),
channel: v.id("channels"),
createdAt: v.number()
})
.index("by_channel", ["channel"])
.index("by_channel_created", ["channel", "createdAt"])
});
Common types:
v.string(), v.number(), v.boolean()v.id("table") - Foreign keyv.array(T), v.object({})v.optional(T), v.union(...)import { ConvexProvider, ConvexReactClient } from "convex/react";
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
<ConvexProvider client={convex}>
<App />
</ConvexProvider>
Usage:
import { useQuery, useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
const messages = useQuery(api.messages.list, { channelId });
const sendMessage = useMutation(api.messages.send);
Server-side preloading:
import { preloadQuery } from "convex/nextjs";
const preloaded = await preloadQuery(api.posts.list);
return <ClientPage preloaded={preloaded} />;
Client component:
"use client";
import { usePreloadedQuery } from "convex/react";
const posts = usePreloadedQuery(preloaded);
Install: npm install @clerk/clerk-react
File: convex/auth.config.ts
import { AuthConfig } from "convex/server";
export default {
providers: [{ domain: process.env.CLERK_JWT_ISSUER_DOMAIN!, applicationID: "convex" }]
} satisfies AuthConfig;
Frontend:
import { ConvexProviderWithClerk } from "convex/react-clerk";
<ConvexProviderWithClerk client={convex} useAuth={useAuth}>
<App />
</ConvexProviderWithClerk>
In functions:
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error("Unauthorized");
// Upload
const storageId = await ctx.storage.store(fileBlob);
await db.insert("files", { storageId, name });
// Download
const url = await ctx.storage.getUrl(storageId);
// Delete
await ctx.storage.delete(storageId);
File: convex/http.ts
import { httpRouter } from "convex/server";
import { httpAction } from "./_generated/server";
const http = httpRouter();
http.route({
path: "/webhooks/stripe",
method: "POST",
handler: httpAction(async (ctx, request) => {
const payload = await request.json();
await ctx.runMutation(internal.payments.process, { payload });
return new Response(null, { status: 200 });
}),
});
export default http;
URL: https://<deployment>.convex.site
Cron Jobs (File: convex/crons.ts):
import { cronJobs } from "convex/server";
const crons = cronJobs();
crons.interval("cleanup", { hours: 1 }, internal.tasks.cleanup);
crons.daily("digest", { hourUTC: 9 }, internal.notifications.send);
export default crons;
Scheduler API (in mutations/actions):
// Schedule for later
await ctx.scheduler.runAfter(delayMs, internal.tasks.process, { id });
// Schedule at specific time
await ctx.scheduler.runAt(timestamp, internal.tasks.remind, { userId });
.filter() on queriesConvexError for structured errors clients can handlectx.runQuery.filter() on queries (use indexes or filter in code)runQuery/runMutation calls (consolidate)import { ConvexError } from "convex/values";
// Throw structured errors
if (!identity) {
throw new ConvexError({ code: "UNAUTHORIZED", message: "Login required" });
}
// Client catches and handles
if (error instanceof ConvexError) {
console.error(error.data.code, error.data.message);
}
Production:
npx convex deploy
With frontend build:
npx convex deploy --cmd 'npm run build'
Environment: Set CONVEX_DEPLOY_KEY for production
Install: npm install convex-test vitest --save-dev
import { convexTest } from "convex-test";
const t = convexTest(schema);
// Test mutations
await t.mutation(api.posts.create, { title: "Test" });
// Test queries
const posts = await t.query(api.posts.list);
expect(posts).toHaveLength(1);
| Problem | Solution |
|---|---|
| Function not found | Run npx convex dev to regenerate types |
| Real-time not working | Check ConvexProvider wraps app |
| Type errors | Restart TypeScript server, regenerate types |
| Deploy fails | Verify CONVEX_DEPLOY_KEY is set |
Advanced topics in references: