Triggers

Event-driven logic that fires automatically on INSERT, UPDATE, or DELETE - on graph labels or document collections. Triggers execute within the same transaction as the triggering operation.

CREATE TRIGGER

-- After insert: auto-create a profile (upsert for idempotency)
CREATE TRIGGER create_profile
  AFTER INSERT ON COLLECTION auth.users
  FOR EACH ROW AS {
    UPSERT DOCUMENT IN profiles NEW.id {
      id: NEW.id,
      username: NEW.username,
      email: NEW.email
    }
  }

-- After update: keep profile in sync (creates if missing)
CREATE TRIGGER sync_profile
  AFTER UPDATE ON COLLECTION auth.users
  FOR EACH ROW AS {
    UPSERT DOCUMENT IN profiles NEW.id {
      id: NEW.id,
      username: NEW.username,
      email: NEW.email
    }
  }

-- Before delete with RAISE to prevent
CREATE TRIGGER protect_admin
  BEFORE DELETE ON COLLECTION auth.users
  FOR EACH ROW AS {
    RAISE 'Cannot delete admin users'
  }

-- Set timestamps on node creation
CREATE TRIGGER set_timestamps
  BEFORE INSERT ON :Project PRIORITY 10
  FOR EACH ROW AS {
    SET NEW.created_on = timestamp(),
        NEW.created_by = current_user()
  }

-- Audit log on delete
CREATE TRIGGER audit_delete
  AFTER DELETE ON :Project
  FOR EACH ROW AS {
    CREATE DOCUMENT IN audit_log uuid() {
      action: 'DELETE',
      old_name: OLD.name,
      deleted_by: current_user(),
      timestamp: timestamp()
    }
  }

Trigger Body Statements

StatementDescription
CREATE DOCUMENT IN coll key { fields }Insert new document (no-op if key exists)
UPSERT DOCUMENT IN coll key { fields }Insert if missing, update fields if exists
MATCH DOCUMENT d IN coll WHERE expr + SET d.field = exprFind and update matching documents
SET NEW.field = exprModify new row (BEFORE INSERT/UPDATE only)
RAISE 'message'Abort the operation (BEFORE triggers only)

OLD / NEW Variables

EventOLDNEW
INSERTnot availablethe new row
UPDATErow before changesrow after changes
DELETEthe deleted rownot available

Management

CREATE OR REPLACE TRIGGER name ...
DROP TRIGGER name
ENABLE TRIGGER name
DISABLE TRIGGER name
SHOW TRIGGERS
SHOW TRIGGERS ON :Label
SHOW TRIGGERS ON COLLECTION auth.users

Built-in Functions in Triggers

FunctionDescription
current_user()UUID of the current session user
current_username()Login username of the current session
is_sync()Whether operation is sync-originated
timestamp()Current epoch ms
uuid()Generate a new UUID v4

Sync Runs Before AFTER Triggers

On a collection write (REST PUT /docs/{collection}/{id} or DELETE), the sync engine projects the document into the graph before any AFTER INSERT / UPDATE / DELETE trigger fires. Trigger bodies can therefore MATCH the synced node and rely on it being present (or absent, for deletes) - there's no race against the sync pass.

Chaining, Backfill & Depth

Trigger chaining: an UPSERT DOCUMENT executed inside a trigger body fires any AFTER triggers defined on the target collection.

Trigger backfill: creating a new trigger automatically processes all existing records in its target, so existing data is immediately consistent with the new logic.

Priority ordering (lower = first, default 100). Recursive trigger firing is capped at 16 levels deep to prevent infinite loops. Use SKIP TRIGGERS on sync rules to prevent cascades.UPSERT DOCUMENT only updates specified fields - existing fields are preserved.