stable

Your first vault

Open a vault, create a typed collection, put and get a record, and run a basic query.

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.

Next

Opt into your first service →