Convex Development
Best practices for robust, secure, performant, cost-effective Convex backends.
Core Principle
Deep modules via the convex/model/ pattern. Most logic should be plain TypeScript; query/mutation wrappers should be thin.
code
convex/ _generated/ # MUST commit to git! model/ # Business logic (testable, reusable) users.ts # Public API (thin wrappers) schema.ts
Critical Rules
- •ALWAYS commit
convex/_generated/- Required for type-checking, CI/CD, team productivity - •Index what you query -
.withIndex()not.filter()for efficient queries - •Paginate everything - Never unbounded
.collect()on user-facing queries - •Trust
ctx.authonly - Never user-provided auth data
Quick Reference
| Need | Use |
|---|---|
| Read data reactively | query |
| Write to database | mutation |
| External APIs, vector search | action |
| Scheduled tasks | internalMutation / internalAction |
Anti-Patterns Scanner
Run scripts/anti_patterns_scanner.py ./convex to detect common issues.
Detailed References
For comprehensive guidance, see:
- •
references/cost-mitigation.md- Bandwidth optimization, indexing, pagination - •
references/embeddings-vectors.md- Vector search patterns, co-location decisions - •
references/query-performance.md- Compound indexes, query segmentation, caching - •
references/security-access.md- Auth patterns, RLS, RBAC, convex-helpers - •
references/schema-migrations.md- Expand/Contract pattern, environment management - •
references/architectural-patterns.md- File organization, state machines, naming
Philosophy
- •Cost First: Bandwidth is often the largest cost. Index aggressively, paginate everything.
- •Security First: Never trust client input. Always use
ctx.auth. - •Reactivity is Power: Use
useQueryfor real-time updates; don't forfeit with one-off fetches. - •Type Safety End-to-End: Leverage Convex's full type chain from database to UI.