Indexes
Indexes speed up document lookups by maintaining a sorted data structure on a field. jcell supports both in-memory indexes (Cache strategy) and native SQL indexes (Delegate strategy).
Schema-Level Indexes​
The simplest way to create an index is in your schema definition:
const userSchema = schema({
email: t.string().index({ unique: true }), // unique index
name: t.string().index(), // simple index
role: t.enum(['admin', 'user'] as const),
})
// Indexes are automatically created when the collection is first used
const db = createDB({ adapter: sqliteAdapter() })
const users = db.collection('users', userSchema)
Programmatic Indexes​
You can also create and drop indexes at runtime:
// Create index
await collection.createIndex('email', { unique: true })
await collection.createIndex('name')
// Drop index
await collection.dropIndex('email')
Adapter Support​
| Feature | File | Memory | SQLite | D1 |
|---|---|---|---|---|
| Schema-level indexes | ✅ (in-memory) | ✅ (in-memory) | ✅ (SQL) | ✅ (SQL) |
| Programmatic create | ✅ | ✅ | ✅ | ✅ |
{ unique: true } | ✅ | ✅ | ✅ | ✅ |
| Drop index | ✅ | ✅ | ✅ | ✅ |
Cache Strategy (File, Memory)​
In-memory indexes use Map<value, Set<id>> for O(1) lookups:
const userSchema = schema({
email: t.string().index({ unique: true }),
})
// Lookup via index
const user = await users.first({ email: 'alice@example.com' })
// Uses the in-memory index for fast lookup
Delegate Strategy (SQLite, D1)​
SQL-level indexes generate real CREATE INDEX statements:
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email ON "users" ("email")
CREATE INDEX IF NOT EXISTS idx_users_name ON "users" ("name")
Important Notes​
- File/Memory adapters: Indexes are rebuilt from in-memory data on startup. They speed up
first()andfind()operations. - SQLite/D1 adapters: Indexes are persisted in the database. They speed up all query operations through native SQL indexing.
- Unique indexes enforce uniqueness at the index level. Inserting a duplicate value throws
DuplicateError.
Best Practices​
- Index fields you query by — especially fields used in
where()andfirst()filters - Use unique indexes for emails, usernames, slugs — enforce uniqueness at the database level
- Don't over-index — each index adds write overhead (the index must be updated on every insert/update)
- Schema-level vs programmatic — use schema-level indexes for permanent indexes, programmatic for temporary ones