diff --git a/content/docs/data-modeling/drivers.mdx b/content/docs/data-modeling/drivers.mdx index 2955712ff6..ffb5eb50ec 100644 --- a/content/docs/data-modeling/drivers.mdx +++ b/content/docs/data-modeling/drivers.mdx @@ -353,20 +353,34 @@ equivalent age-based reap. ## Memory Driver The in-memory driver keeps records in plain in-process objects (queried via -[`mingo`](https://github.com/kofrasa/mingo)). Data is lost when the process exits. +[`mingo`](https://github.com/kofrasa/mingo)). It is the **last-resort fallback** in dev mode: `objectstack dev` prefers native SQLite (`better-sqlite3`), falls back to the pure-JS WASM SQLite driver if the native binary is unavailable, and only drops to the in-memory driver if WASM also fails to load. Set `OS_DATABASE_DRIVER=memory` to select it explicitly. +**Whether data survives the process depends on how the driver is built** (#4083): + +| How it is built | Persistence | +| :--- | :--- | +| A **declared datasource** — `{ driver: 'memory' }` in a stack/app config | **Ephemeral.** Nothing is written to disk unless the declaration sets `config.persistence` — and when it does, the destination is scoped per datasource, so two memory datasources never share one file. | +| `new InMemoryDriver()` **constructed directly** | `persistence: 'auto'` — under Node that means a JSON file at `.objectstack/data/memory-driver.json`, relative to the process's working directory, reloaded on the next boot. | + +Pass `persistence: false` for a driver you construct yourself and want purely in +memory — a test, for instance, which should neither depend on nor leave behind +state in the working directory. Two directly-constructed `'auto'` drivers in one +process still share that single default path. + ```typescript import { InMemoryDriver } from '@objectstack/driver-memory'; -new InMemoryDriver(); +new InMemoryDriver({ persistence: false }); // pure memory +new InMemoryDriver(); // 'auto' — file-backed under Node ``` -Use the memory driver for unit tests. It requires no setup and runs instantly. +Use the memory driver for unit tests. It requires no setup and runs instantly — +with `persistence: false`, so one run cannot see what an earlier run left behind. ## Local Environment Runtime diff --git a/packages/spec/src/data/driver/memory.zod.ts b/packages/spec/src/data/driver/memory.zod.ts index cd70ec19e3..232c486b5a 100644 --- a/packages/spec/src/data/driver/memory.zod.ts +++ b/packages/spec/src/data/driver/memory.zod.ts @@ -216,8 +216,19 @@ export const MemoryConfigSchema = lazySchema(() => z.object({ * new InMemoryDriver({ persistence: false }) * // Custom adapter for serverless * new InMemoryDriver({ persistence: { adapter: upstashAdapter } }) + * + * **A datasource declared with `driver: 'memory'` is ephemeral unless this + * key is set (#4083).** `'auto'` is the default only for a driver you + * construct yourself. The shared datasource factory + * (`createDefaultDatasourceDriverFactory`) passes `false` when the + * declaration says nothing, so a declared memory datasource cannot silently + * become a file-backed store in the process's working directory — matching + * `objectstack dev`, which already reads an explicit memory driver as the + * user opting out of persistence. Set this key to opt back in; when you do + * without naming a `path`/`key`, the factory scopes the destination per + * datasource, so two memory datasources never share one file. */ - persistence: MemoryPersistenceConfigSchema.or(z.literal(false)).default('auto').describe('Persistence configuration (defaults to auto-detect)'), + persistence: MemoryPersistenceConfigSchema.or(z.literal(false)).default('auto').describe('Persistence configuration (auto-detect by default; a declared memory datasource is ephemeral unless set)'), /** * Fields to index for faster lookups.