Guidelines for building production-ready Convex apps covering function organization, query patterns, validation, TypeScript usage, error handling, and the Zen of Convex design philosophy
No setup needed. Let our cloud agents run this skill for you.
Select Provider
Select Model
Claude Sonnet 4.5
$0.20/task
Best for coding tasks
Environment setup included
Convex Best Practices
Build production-ready Convex applications by following established patterns for function organization, query optimization, validation, TypeScript usage, and error handling.
Code Quality
All patterns in this skill comply with @convex-dev/eslint-plugin. Install it for build-time validation:
npm i @convex-dev/eslint-plugin --save-dev
// eslint.config.jsimport { defineConfig } from "eslint/config";import convexPlugin from "@convex-dev/eslint-plugin";export default defineConfig([ ...convexPlugin.configs.recommended,]);
import { Id, Doc } from "./_generated/dataModel";// Use Id type for document referencestype UserId = Id<"users">;// Use Doc type for full documentstype User = Doc<"users">;// Define Record types properlyconst userScores: Record<Id<"users">, number>
Internal vs Public Functions
// Public function - exposed to clientsexport const getUser = query({ args: { userId: v.id("users") }, returns: v.union( v.null(), v.object({ /* ... */ }), ), handler: async (ctx,
Examples
Complete CRUD Pattern
// convex/tasks.tsimport { query, mutation } from "./_generated/server";import { v } from "convex/values";import { ConvexError } from "convex/values"
Best Practices
Never run npx convex deploy unless explicitly instructed
Never run any git commands unless explicitly instructed
Always define return validators for functions
Use indexes for all queries that filter data
Make mutations idempotent to handle retries gracefully
Use ConvexError for user-facing error messages
Organize functions by domain (users.ts, tasks.ts, etc.)
Use internal functions for sensitive operations
Leverage TypeScript's Id and Doc types
Common Pitfalls
Using filter instead of withIndex - Always define indexes and use withIndex
Missing return validators - Always specify the returns field
Non-idempotent mutations - Check current state before updating
Reading before patching unnecessarily - Patch directly when possible
Not handling null returns - Document IDs might not exist