Your first vault
Every record lives at a (vault, collection, id) triple. A vault is a tenant / company namespace ("acme", "firm-2026"); a collection is a typed record set inside it ("invoices", "clients").
Continuing from Install, open a vault and create a typed collection:
type Invoice = { id: string; amount: number; customer: string }
const vault = await db.openVault('acme')
const invoices = vault.collection<Invoice>('invoices')
await invoices.put('inv-1', { id: 'inv-1', amount: 8500, customer: 'ABC Trading' })
const inv = await invoices.get('inv-1')
// → { id: 'inv-1', amount: 8500, customer: 'ABC Trading' }
openVault() opens and caches a vault — calling it again with the same name is idempotent. The type parameter on collection<Invoice>() carries through get, put, query, and scan. get() returns the decrypted record, or null if no record exists at that id — the store and any transport in between only ever handled the encrypted form.
Query it
The collection's chainable query builder gives you where / orderBy / limit:
const bigInvoices = await invoices.query()
.where('amount', '>', 1000)
.toArray()
[
{ "id": "inv-1", "amount": 8500, "customer": "ABC Trading" }
]
.where(field, op, value) supports ==, !=, <, <=, >, >=, in, contains, startsWith, and between. Chain .orderBy() / .limit() / .offset() before .toArray(), or call .first() / .count() instead.