FumaDB is the internal database abstraction layer and ORM system used across the Executor monorepo. It provides a unified interface for interacting with relational data while abstracting the underlying engine (SQLite for local/desktop hosts and PostgreSQL for cloud/self-host environments). FumaDB handles schema definition, row-level security (RLS) policies via an internal "Owner Policy" system, and automated migrations.
FumaDB sits between the Executor SDK and the physical database drivers. It uses a custom schema definition language that compiles to the specific requirements of the target host.
FumaDB supports multiple backends through a unified adapter interface. This allows the core logic to remain agnostic of whether it is running against a local libsql file or a high-concurrency PostgreSQL instance.
apps/local and apps/desktop for local data persistence apps/local/src/db/v1-v2-migration.ts3-5apps/cloud for multi-tenant, distributed storage apps/cloud/drizzle/meta/_journal.json3The following diagram illustrates how a database request flows from the SDK through the FumaDB abstraction layer to the physical storage.
Sources: packages/core/sdk/src/core-schema.ts1-13 packages/core/sdk/src/fuma-runtime.ts4-10
FumaDB enforces a strict multi-tenancy model at the schema level. Tables are categorized by their isolation level using specific factory functions.
| Scoping Function | Description | Isolation Key |
|---|---|---|
unscopedExecutorTable | Global tables shared across the entire instance. | id packages/core/sdk/src/core-schema.ts41-52 |
tenantExecutorTable | Tables shared within a single Tenant (e.g., Integration catalog). | tenant packages/core/sdk/src/core-schema.ts55-81 |
ownedExecutorTable | Tables isolated by User or Org (e.g., Connections, Policies). | tenant, owner, subject packages/core/sdk/src/core-schema.ts85-109 |
The following diagram maps the logical database concepts to the actual TypeScript entities defined in the schema.
Sources: packages/core/sdk/src/core-schema.ts114-156 packages/core/sdk/src/ids.ts1-15
FumaDB manages two types of migrations: structural schema changes (via Drizzle) and data migrations (internal "Ledger" system).
Structural changes are tracked in a journaled format. Both SQLite and PostgreSQL maintain separate migration histories to account for dialect differences.
apps/cloud/drizzle/meta/_journal.json apps/cloud/drizzle/meta/_journal.json1-76apps/local/drizzle/meta/_journal.json apps/local/drizzle/meta/_journal.json1-35A significant portion of the FumaDB logic in apps/local is dedicated to the "V1 to V2" migration. This process involves:
LOCAL_V1_V2_LEDGER_NAME to ensure migrations only run once apps/local/src/db/v1-v2-migration.ts174-183CredentialProvider system (Keychain or File) apps/local/src/db/v1-v2-migration.ts111-136FumaDB provides a sandboxed storage API for plugins called PluginStorage. This allows plugins to persist their own data (e.g., execution history, state) without modifying the core schema.
Plugins define collections using definePluginStorageCollection. These collections are automatically partitioned by the owner of the execution.
Sources: packages/core/sdk/src/plugin-storage.test.ts15-27 packages/core/sdk/src/plugin-storage.ts1-20
The wiring of the database depends on the host environment.
The Local host uses libsql to open a local file. It runs a v1-v2-migration check on every boot before the API server starts apps/local/src/db/v1-v2-migration.ts1-35 It also manages "data directory ownership" to ensure the database file is accessible by the current user apps/local/src/db/data-dir-ownership.ts1-10
The Cloud host connects to a PostgreSQL instance. Because it runs on Cloudflare Workers, it utilizes Hyperdrive for connection pooling and Durable Objects for session-specific state that doesn't require full relational persistence apps/cloud/drizzle/meta/_journal.json1-10
Sources: apps/local/src/db/v1-v2-migration.ts38-40 apps/cloud/drizzle/meta/_journal.json1-5
Refresh this wiki