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
| Statement | Description |
|---|---|
| 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 = expr | Find and update matching documents |
| SET NEW.field = expr | Modify new row (BEFORE INSERT/UPDATE only) |
| RAISE 'message' | Abort the operation (BEFORE triggers only) |
OLD / NEW Variables
| Event | OLD | NEW |
|---|---|---|
| INSERT | not available | the new row |
| UPDATE | row before changes | row after changes |
| DELETE | the deleted row | not 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
| Function | Description |
|---|---|
| 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.