Skip to content

Core concepts

An entity is a table definition. A record is a row. Record data lives in a JSONB column, which is why adding a field does not require a migration, and why entities can evolve without downtime.

Every record has a record_id. Entities usually also carry their own business key — issue_id, component_id — which is what upsert and delete match on.

Some entities are physical tables rather than JSONB, prefixed with __: __user, __group. Records can reference them like anything else.

The sharpest line in the platform.

Configuration is structure: entities, guest code, automations, groups, share rules, senders. It is retrievable, diffable, and deployable between workspaces.

Data is records. It moves with upsert and query, never with deploy.

TypeScript you write runs sandboxed: no filesystem, no network, no Deno global. Everything reachable comes through a platform:* module. See the runtime overview.

Four kinds, by what starts them:

KindRuns when
TriggerA record changes
Scheduled jobA cron schedule fires
ControllerA view calls a method
ViewA user opens a page

Triggers receive arrays. Saving one record and importing ten thousand call the same method. Code that assumes a single record still works — it just becomes ten thousand round trips.

Query once for the batch, build a Map, then loop.

Guest code runs as the user who triggered it. Plain sql is filtered by row-level security, so it only sees what that user may see. Scheduled jobs have no triggering user and run as the built-in SYSTEM account.

sql.systemMode bypasses that filtering entirely. It exists for work with no user context, and it is the one place a mistake becomes a data leak.

A workspace is an isolated tenant with its own schema, users, and configuration. One account can belong to several. CLI commands take --workspace to act in a specific one, and credentials are stored per alias — so a single machine can address production, staging, and local without re-authenticating.

A page is a custom React view attached to an entity, either as its detail view or its create form. Pages are compiled at runtime and call controllers for data.