Comprehensive guide for building Convex backends with TypeScript. Covers function syntax, validators, schemas, queries, mutations, actions, scheduling, and file storage.
Reference these guidelines when:
| Category | Impact | Description |
|---|---|---|
| Function Syntax | CRITICAL | New function syntax with args/returns/handler |
| Validators | CRITICAL | Type-safe argument and return validation |
| Schema Design | HIGH | Table definitions, indexes, system fields |
| Query Patterns | HIGH | Efficient data fetching with indexes |
| Mutation Patterns | MEDIUM | Database writes, patch vs replace |
| Action Patterns | MEDIUM | External API calls, Node.js runtime |
| Scheduling | MEDIUM | Crons and delayed function execution |
| File Storage | LOW | Blob storage and metadata |
// Public functions (exposed to clients)
import { query, mutation, action } from "./_generated/server";
// Internal functions (only callable from other Convex functions)
import {
internalQuery,
internalMutation,
internalAction,
} from "./_generated/server";
export const myFunction = query({
args: { name: v.string() },
returns: v.string(),
handler: async (ctx, args) => {
return "Hello " + args.name;
},
});
| Type | Validator | Example |
|---|---|---|
| String | v.string() |
"hello" |
| Number | v.number() |
3.14 |
| Boolean | v.boolean() |
true |
| ID | v.id("tableName") |
doc._id |
| Array | v.array(v.string()) |
["a", "b"] |
| Object | v.object({...}) |
{name: "x"} |
| Optional | v.optional(v.string()) |
undefined |
| Union | v.union(v.string(), v.number()) |
"x" or 1 |
| Literal | v.literal("status") |
"status" |
| Null | v.null() |
null |
// Public functions
import { api } from "./_generated/api";
api.example.myQuery; // convex/example.ts → myQuery
// Internal functions
import { internal } from "./_generated/api";
internal.example.myInternalMutation;
// Schema
messages: defineTable({...}).index("by_channel", ["channelId"])
// Query
await ctx.db
.query("messages")
.withIndex("by_channel", (q) => q.eq("channelId", channelId))
.order("desc")
.take(10);
args and returns validators on all functionsv.null() for void returns - never omit return validatorwithIndex() not filter() - define indexes in schemainternalQuery/Mutation/Action for private functionsctx.db - use runQuery/runMutation insteadFor the complete guide with all rules and detailed code examples, see: AGENTS.md