Skip to main content

The Plugin Data Model

A plugin owns its data. The core provides the workspace and workflow_execution tables; your plugin provides everything domain-specific — and clips onto the core through a small, disciplined set of tables. This is that data model. (The Default Plugin ER Diagram shows it visually.)

The two required tables

Entity object table — named after your entity (e.g. default_plugin_thing). It holds your domain fields, and optionally entity-level pointers like active_workspace_id and final_workspace_id (both FKs to core workspace, nullable). Not every plugin needs those pointers.

Join table — named {entity_slug}_workspace, linking your entity to core workspaces. It has required columns:

  • {entity_slug}_id — FK to your entity object;
  • workspace_id — FK to core workspace;
  • is_deleted and is_archivedplugin-owned booleans.

A unique constraint on (entity_id, workspace_id) keeps the link clean. Your queries must filter on is_deleted / is_archived to hide deleted/archived workspaces — because core workspaces are never actually deleted, deletion and archival are your soft-flags on this table.

Domain tables

Beyond the two required tables, add whatever your domain needs. The default plugin adds default_plugin_section (grouping), default_plugin_output (workflow results, with an output_type and a nullable workflow_execution_id), and default_plugin_input (append-only operator input), plus helper views. Reference core tables via FKs where useful — but never the other direction.

The invariant that governs it all

Every foreign key points from a plugin table to a core table (or to another plugin table) — never from a core table to a plugin table. The core is unaware of your plugin's shape. This one-way rule is what keeps the boundary clean: you can build any data model you like, as long as the arrows only point inward.

Naming conventions

  • Prefix every plugin table with your entity slug (avoids collisions; plugin tables share the circus schema with core).
  • Singular nouns (default_plugin_thing, not _things); snake_case; FK columns as {referenced_table}_id.

Where the schema lives

Your tables are defined by your migrations (plugins/{entity_slug}/migrations/), which are the authoritative schema for your plugin — see Writing Plugin Migrations. The default plugin's migrations are the maintained reference to study.