How reactivity works
The reactive database model in Convex is built on three core principles:- Automatic dependency tracking - When you run a query, Convex tracks which documents and indexes your query reads
- Change detection - When a mutation modifies data, Convex identifies which queries are affected
- Automatic re-execution - Affected queries automatically re-run and push updates to subscribed clients
Reading from the database
The database reader interface (ctx.db) provides two primary entry points:
Fetching by ID
Usedb.get() to fetch a single document by its ID:
Querying multiple documents
Usedb.query() to build more complex queries:
Always prefer
.withIndex() over .filter() for better performance. Indexes allow Convex to efficiently find matching documents, while filters must scan all documents.Writing to the database
Mutations provide a database writer interface (ctx.db) with four write operations:
Insert
Add new documents to a table:_id and _creationTime) are added automatically.
Patch
Shallow merge updates into an existing document:undefined to remove them.
Replace
Completely replace a document (except system fields):Delete
Remove a document from the database:Transactional guarantees
All reads and writes within a single query or mutation are atomic and isolated:- Queries see a consistent snapshot of the database at a single point in time
- Mutations execute all writes atomically - either all succeed or all fail
- No partial states or race conditions - you never see inconsistent data
System tables
Convex provides read-only access to system tables throughctx.db.system:
_storage- File metadata for stored files_scheduled_functions- State of scheduled functions
Query patterns
The database reader supports several patterns for consuming query results:Optimistic concurrency control
Convex uses optimistic concurrency control (OCC) for mutations. If a mutation reads data that was modified by another concurrent mutation, Convex automatically retries the mutation with fresh data. You don’t need to handle this explicitly - Convex manages retries transparently. Just write your mutation logic as if it runs alone:Real-time updates
When you use queries in your client application with React hooks likeuseQuery, the results automatically update when underlying data changes:
Next steps
- Learn about Functions to understand queries, mutations, and actions
- Define Schemas to validate your data and get TypeScript types
- Explore Real-time sync to understand the synchronization protocol