Convex Code Review
Security Checklist
1. Argument AND Return Validators
- All public
query,mutation,actionhaveargsvalidators - All functions have
returnsvalidators - No
v.any()for sensitive data - HTTP actions validate request body (Zod recommended)
Search: query({, mutation({, action({ - check each has args: AND returns:
2. Error Handling
- Uses
ConvexErrorfor user-facing errors (not plainError) - Error codes are structured:
{ code: "NOT_FOUND", message: "..." } - No sensitive info leaked in error messages
Search: throw new Error should be throw new ConvexError
3. Access Control
- All public functions check
ctx.auth.getUserIdentity()where needed - Uses auth helpers (
requireAuth,requireRole) - No client-provided email/username for authorization
- Row-level access verified (ownership checks)
Search: ctx.auth.getUserIdentity should appear in most public functions
4. Internal Functions
-
ctx.runQuery,ctx.runMutation,ctx.runActionuseinternal.*notapi.* -
ctx.scheduler.runAfterusesinternal.*notapi.* - Crons in
crons.tsuseinternal.*notapi.*
Search: api. in convex directory - should not be used for scheduling/running
5. Table Names in DB Calls
- All
ctx.db.get,patch,replace,deleteinclude table name as first arg
Search: db.get(, db.patch( - first arg should be quoted string
Performance Checklist
6. Database Queries
- No
.filter()on queries (use.withIndex()or filter in code) -
.collect()only with bounded results (<1000 docs) - Pagination for large result sets
Search: \.filter\(\(?q, \.collect\(
7. Indexes
- No redundant indexes (
by_foo+by_foo_and_bar) - All filtered queries use
.withIndex() - Index names include all fields
Review: schema.ts index definitions
8. Date.now() in Queries
- No
Date.now()in query functions - Time filtering uses boolean fields or client-passed timestamps
9. Promise Handling
- All promises awaited (
ctx.scheduler,ctx.db.*)
ESLint: no-floating-promises
Architecture Checklist
10. Action Usage
- Actions have
"use node";if using Node.js APIs -
ctx.runActiononly when switching runtimes - No sequential
ctx.runMutation/ctx.runQuery(combine for consistency)
11. Code Organization
- Business logic in helper functions (
convex/model/) - Public API handlers are thin wrappers
- Auth helpers in
convex/lib/auth.ts
12. Transaction Consistency
- Related reads in same query/mutation
- Batch operations in single mutation
- Mutations are idempotent
Quick Regex Searches
| Issue | Regex | Fix |
|---|---|---|
.filter() | \.filter\(\(?q | Use .withIndex() |
| Missing returns | handler:.*async without returns: | Add returns: |
| Plain Error | throw new Error\( | Use ConvexError |
| Missing table name | db\.(get|patch)\([^"'] | Add table name |
Date.now() in query | Date\.now\(\) | Remove from queries |
api.* scheduling | api\.[a-z] | Use internal.* |
Production Readiness
- Security: Validators + ConvexError + Auth checks + Internal functions
- Performance: Indexes + Bounded queries + No Date.now()
- Architecture: Helper functions + Proper action usage + "use node"
- Code Quality: Awaited promises + Table names + Return validators