schema.ts:packages/convex/schema.ts using Convex’s type-safe schema definition.
Schema Overview
The database consists of three main tables and one system table:Cards Table
The primary table storing all user content:Fields
Card Types
Eight supported card types fromschema.ts:packages/convex/schema.ts:6-15:
Metadata Structure
Link Preview Metadata
For link cards, rich preview data is stored:File Metadata
For file-based cards (image, video, audio, document):Color Palette
For palette cards and images:Processing Status
Tracks the progress of each AI processing stage fromschema.ts:packages/convex/schema.ts:32-54:
Indexes
Optimized indexes for common query patterns fromschema.ts:packages/convex/schema.ts:213-224:
The
by_user index was removed as redundant - by_user_deleted serves the same purpose with partial index matching per Convex best practices.Search Indexes
Full-text search across multiple fields fromschema.ts:packages/convex/schema.ts:226-271:
Search indexes eliminate full table scans for tag and color searches, significantly improving performance.
API Keys Table
Stores API keys for programmatic access fromschema.ts:packages/convex/schema.ts:148-160:
Indexes
Desktop Auth Codes Table
Manages authentication codes for desktop app fromschema.ts:packages/convex/schema.ts:162-174:
Indexes
The
codeHash field is deprecated for backward compatibility. New records use polling-only authentication and do not set this field.System Tables
_storage
Convex’s built-in file storage table (not defined in schema):ctx.db.system.get():
Type Exports
The schema exports TypeScript types for use throughout the application:Query Examples
Get Cards by Type
Search Cards
Check for Duplicate URLs
Get Favorites
Schema Migrations
When changing the schema:- Update validators in
schema.ts - Deploy schema changes:
bun run dev:convex - Convex automatically handles additive changes (new optional fields)
- For breaking changes, write migration functions
Best Practices
Use indexes for all queries
Use indexes for all queries
Never use
.filter() on queries without an index. Always define an index in the schema for your query pattern.Flatten fields for search
Flatten fields for search
Store flattened versions of nested data for efficient search indexing:
Use compound indexes wisely
Use compound indexes wisely
Compound indexes must be queried in order. Create separate indexes for different query patterns:
Keep optional fields optional
Keep optional fields optional
Use
v.optional() for all fields that may not be present initially or for all card types. This prevents validation errors during card creation.