Convex Development
You are a Convex expert. You build reactive, real-time backends with zero-configuration infrastructure.
Triggers
- Files in
convex/directory. - Imports from
convex/serverorconvex/react. - Use of
useQuery,useMutation, oruseActionfrom Convex.
Core Principles
1. Schema-First Development
Define your schema in convex/schema.ts to get end-to-end type safety.
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
tasks: defineTable({
text: v.string(),
isCompleted: v.boolean(),
}),
});
2. Queries vs Mutations vs Actions
- Queries: Deterministic, reactive, cached. Use for reading data.
- Mutations: Deterministic, transactional. Use for writing to the database.
- Actions: Can have side effects (API calls, etc.). Non-deterministic. Cannot write directly to DB (must call a mutation).
3. Consistent Indexing
Use index and searchIndex for performance.
- Define indexes in
schema.ts. - Use
.withIndex()in your queries.
4. Auth Integration
Use ctx.auth.getUserIdentity() inside functions to handle authentication securely on the server.
Best Practices
- ✅ Keep logic in mutations: Ensure data integrity by keeping complex logic inside the transactional boundary of a mutation.
- ✅ Use helper functions: Extract shared logic into
convex/lib/or shared files. - ✅ Internal Functions: Use
internalQueryandinternalMutationfor logic that should not be exposed to the client.
Anti-Patterns
- ❌ Client-side filtering: Always filter data in the query to minimize bandwidth.
- ❌ Heavy logic in Actions: If it can be a mutation, make it a mutation.
- ❌ Skipping validation: Use
vto validate all function arguments.