stable

See the ciphertext

Persist your vault to disk with to-file, open the stored file, and see for yourself that the store only ever holds ciphertext.

The Install page claims the store never sees your plaintext. Don't take the claim — look at the bytes. Swap the in-memory default for to-file, which persists each record as a JSON file you can open:

pnpm add @noy-db/to-file
import { createNoydb } from '@noy-db/hub'
import { toFile } from '@noy-db/to-file'

const db = await createNoydb({
  store: toFile({ dir: './data' }),
  user: 'me',
  secret: 'correct horse battery staple',
})

const vault = await db.openVault('acme')
const invoices = vault.collection('invoices')
await invoices.put('inv-1', { id: 'inv-1', amount: 8500, customer: 'ABC Trading' })

Now open what the store wrote — cat ./data/acme/invoices/inv-1.json:

{
  "_noydb": 1,
  "_v": 1,
  "_ts": "2026-07-15T15:31:54.149Z",
  "_iv": "OIGbecaDduQOQqO+",
  "_data": "ruPaj9T50xSQoRfFM3y8NfmlXApnBRzz/Ym3XaqGlqZzao93e/LR4Pox+d0N1nJoWmhypqXAIaEaJZRBcITEmsY9jiFD",
  "_by": "me"
}

That file is an envelope — the only shape any to-* store ever handles. The record's fields (amount, customer, even the field names) are inside _data, encrypted; _iv is the per-write initialization vector; the cleartext parts (_v, _ts, _by) are versioning metadata the store needs to do its job. grep 8500 -r ./data finds nothing.

The same directory also holds acme/_keyring/me.json — your keyring, whose per-collection data keys are themselves wrapped under a key derived from your secret — and acme/_meta/policy.json, the deliberately-plaintext unlock policy. Nothing readable requires anything readable to be stored: whoever holds this directory (a disk, a cloud bucket, a backup) holds ciphertext and can neither run your queries nor read your records.

The negative control

Encryption is on by default and can only be disabled explicitly. Run the same code with encrypt: false (testing only — no privacy guarantee) and read the file again:

{
  "_noydb": 1,
  "_v": 1,
  "_ts": "2026-07-15T15:32:09.970Z",
  "_iv": "",
  "_data": "{\"id\":\"inv-1\",\"amount\":8500,\"customer\":\"ABC Trading\"}",
  "_by": "me"
}

Same envelope shape, plaintext _data, empty _iv — that's the entire difference the secret makes, and it's the difference between a store you must trust and a store you don't have to.

In the browser

@noy-db/to-browser-idb gives you the same experiment in a web app: write a record, open DevTools → Application → IndexedDB, and inspect the stored envelopes — _data is the same opaque ciphertext there. See Core 05 — Stores for the store catalog.

Next