Skip to main content

Trigger Functions

Trigger functions execute automatically when data changes in a collection. Use them for validation, transformation, notifications, and integrations.

How It Works

  1. Configure which collection to monitor
  2. Select which operations trigger execution (POST, PUT, PATCH, DELETE)
  3. Write JavaScript code or configure an external webhook
  4. Function runs automatically on matching operations

Configuration

Basic Settings

SettingDescription
NameUnique identifier for the function
DescriptionOptional documentation
EnabledToggle to enable/disable without deleting
CollectionThe collection to monitor
MethodsWhich operations trigger execution

Triggering Methods

MethodWhen It Fires
POSTNew item created
PUTItem replaced
PATCHItem updated
DELETEItem deleted

Select one or more methods. The function fires for each matching operation.

Execution Context

What Your Code Receives

ObjectDescription
itemThe record being created, updated, or deleted
meThe user who triggered the change
reqRequest details (method, headers, query)
apiAPI information
secretsConfigured secrets
collectionNameName of the collection being processed
validationErrorsArray for validation errors (returns 400 if non-empty)

Token Options

Control whose permissions the function uses:

OptionDescription
NoneNo authentication (anonymous)
Current UserExecute as the user who triggered the change
Service AccountExecute with service account permissions

Execution Control

OptionDescription
Skip Security PolicyBypass row-level access control
Skip RolesIgnore role-based permissions
Halt on ErrorStop the operation if the function crashes unexpectedly

Understanding Halt on Error

Halt on Error controls what happens when your function crashes due to unexpected errors (runtime errors, failed external requests, etc.) — it does NOT affect validation errors.

ScenarioHalt on Error ONHalt on Error OFF
Validation errors (validationErrors)Operation blockedOperation blocked
Runtime error (e.g., undefined variable)Operation blockedOperation continues
External fetch failsOperation blockedOperation continues

Example: You have a trigger that validates input AND syncs to an external CRM:

// Validation - always blocks if invalid
if (!item.email) {
validationErrors.push('Email is required');
}

// External sync - might fail
await fetch('https://crm.example.com/sync', { ... });
  • With Halt on Error ON: If CRM is down, the insert is blocked
  • With Halt on Error OFF: If CRM is down, the insert proceeds anyway (validation still works)

Use Cases

Data Validation

Use the validationErrors array to reject invalid data. If this array has any items when the function completes, the operation returns 400 Bad Request with the errors in the response body.

// Reject orders with invalid totals
if (item.total < 0) {
validationErrors.push('Order total cannot be negative');
}

if (!item.items || item.items.length === 0) {
validationErrors.push('Order must have at least one item');
}

if (item.total > 10000 && !item.approvedBy) {
validationErrors.push('Orders over $10,000 require approval');
}

Multiple validation errors can be collected and returned together:

["Order total cannot be negative", "Order must have at least one item"]
Validation vs Runtime Errors
  • Validation errors (validationErrors.push(...)) — Returned to the client in the response body
  • Runtime errors (undefined variables, failed fetch, etc.) — Only logged server-side, not exposed to client

Data Transformation

Transform values before saving:

// Auto-generate slug from title
item.slug = item.title
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '');

// Set timestamps
item.updatedAt = new Date().toISOString();
item.updatedBy = me.id;

Notifications

Send notifications on changes (requires paid tier):

// Notify when order status changes
if (item.status === 'shipped') {
await fetch('https://api.email-service.com/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
to: item.customerEmail,
subject: 'Your order has shipped!',
body: `Order ${item.orderNumber} is on its way.`
})
});
}

External Sync

Sync data with external systems (requires paid tier):

// Sync customer to CRM
await fetch('https://crm.example.com/api/contacts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${secrets.CRM_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: item.email,
name: item.name,
source: 'website'
})
});

Cascade Operations

Perform related operations using built-in methods:

// When a project is deleted, archive its tasks
if (req.method === 'DELETE') {
const tasksRes = await get(`tasks?filter=projectId eq "${item.id}"`);
for (const task of tasksRes.data) {
await patch(`tasks/${task.id}`, { archived: true });
}
}

External Endpoint Action

Instead of JavaScript, call an external webhook:

SettingDescription
URLThe webhook endpoint to call
Custom HeadersAdditional headers to include
Send TokenInclude authentication token
Halt on ErrorStop if webhook fails

The webhook receives the same context as JavaScript functions.

Best Practices

  • Keep functions focused — One function, one responsibility
  • Use validationErrors for user-facing errors — These are returned in the response
  • Use built-in methodsget(), post(), patch(), del() for internal API calls
  • Use Halt on Error carefully — Enable when external failures should block the operation
  • Test thoroughly — Use the built-in test runner before enabling
  • Log important events — Use log() for debugging and auditing