This skill should be used when implementing Convex mutation functions. It provides comprehensive guidelines for defining, registering, calling, and scheduling mutations, including database operations, transactions, and scheduled job patterns.
This skill provides specialized guidance for implementing Convex mutation functions, including best practices for function definition, registration, database operations, and scheduling patterns.
Use this skill when:
insert, patch, replace, delete)ctx.scheduler.runAfterThis skill includes comprehensive reference documentation in references/mutation-guidelines.md that covers:
mutation and internalMutation)ctx.runQuery and ctx.runMutation)api and internal objects)ctx.db.insert() - Create new documentsctx.db.patch() - Shallow merge updates into existing documentsctx.db.replace() - Fully replace existing documentsctx.scheduler.runAfter() to queue background jobs
references/mutation-guidelines.md to understand the complete mutation patternsinsert, patch, replace) based on your needsctx.scheduler.runAfter for long-running operationsctx.db.patch() for partial updates and ctx.db.replace() for full replacementsctx.scheduler.runAfter() to schedule actions (e.g., AI responses, notifications)null auth state; use internal functions insteadnull implicitly if your mutation doesn't have an explicit return valueimport { mutation, internalAction } from "./_generated/server";
import { v } from "convex/values";
import { internal } from "./_generated/api";
export const sendMessage = mutation({
args: {
channelId: v.id("channels"),
authorId: v.id("users"),
content: v.string(),
},
handler: async (ctx, args) => {
// Validate channel and user exist
const channel = await ctx.db.get(args.channelId);
if (!channel) {
throw new Error("Channel not found");
}
// Insert message into database
await ctx.db.insert("messages", {
channelId: args.channelId,
authorId: args.authorId,
content: args.content,
});
// Schedule AI response generation (transactional)
await ctx.scheduler.runAfter(0, internal.functions.generateResponse, {
channelId: args.channelId,
});
return null;
},
});
export const updateUserStatus = mutation({
args: {
userId: v.id("users"),
status: v.string(),
},
handler: async (ctx, args) => {
// Patch updates an existing document with shallow merge
await ctx.db.patch(args.userId, {
status: args.status,
lastUpdated: Date.now(),
});
return null;
},
});
For more detailed information and additional patterns, refer to the complete reference documentation.