Convex DB Best Practices
Follow this workflow when editing Convex database code.
Quick Workflow
- •Identify the Convex surface area.
- •Audit for common anti-patterns using search patterns.
- •Apply fixes using the guidance below.
- •If unsure about a rule, read
references/convex-best-practices.mdfor detailed rationale and examples.
Identify Scope
- •Scan
convex/for the relevant files and functions. - •Confirm whether the change touches queries, mutations, actions, indexes, or scheduled functions.
Audit Search Patterns
Use rg to find likely hotspots:
- •
\.filter\(\(?qfor query filters - •
\.collect\(for unbounded collects - •
ctx\.run(Query|Mutation|Action)for run* usage - •
ctx\.schedulerandcronsfor scheduling - •
query\(|mutation\(|action\(|internalQuery\(|internalMutation\(|httpAction\(for validator/access control checks - •
ctx\.db\.(get|patch|replace|delete)\(for explicit table name usage - •
Date\.now\(\)for time in queries - •
api\.usage insideconvex/(should usually beinternal.)
Fix Guidance (Short)
- •Prefer indexes (
withIndex/withSearchIndex) over.filteror in-code filtering when result sets can be large. - •Avoid
.collect()on potentially unbounded queries; use indexes,paginate,take, or denormalize. - •Ensure all public functions have argument validators and access control checks.
- •Schedule and
ctx.run*onlyinternal.*functions. - •Replace
runActionwith plain helper functions unless crossing runtimes. - •Avoid sequential
ctx.runQuery/ctx.runMutationcalls that need consistency; combine into single internal function. - •Avoid
ctx.runQuery/ctx.runMutationinside queries and mutations unless required (components or partial rollback). - •Always pass table name into
ctx.db.get/patch/replace/delete. - •Avoid
Date.now()inside queries; use scheduled flags or pass time as arg.
Output Expectations
- •Provide a concise list of findings with file paths and suggested fixes.
- •Apply edits directly when requested; otherwise propose a patch.
- •Note any assumptions or places where a tradeoff exists.