Docs/Development

Triggers

Automatic actions that execute in response to database events.

Triggers & Automation

Overview

Triggers are automatic actions that execute in response to database events. They enable you to implement business logic, maintain data integrity, and integrate with external systems without manual intervention.


Trigger Types

Event Types

EventWhen FiredSync/AsyncUse Cases
before_createBefore INSERTSyncValidation, defaults, transformations
after_createAfter INSERTSyncNotifications, related records
before_updateBefore UPDATESyncValidation, field protection
after_updateAfter UPDATESyncAudit logs, cache invalidation
before_deleteBefore DELETESyncDependency checks, archiving
after_deleteAfter DELETESyncCleanup, notifications

Creating Triggers

Basic Trigger Structure

typescript
// triggers/users/after-create.ts

import { TriggerDefinition } from '@algorithmshift/runtime';

export const trigger: TriggerDefinition = {
  entity: 'users',
  event: 'after_create',
  name: 'Create User Profile',
  description: 'Creates a profile and sends welcome email',
  enabled: true,
  priority: 10,

  condition: (record, context) => {
    return record.role === 'customer';
  },

  handler: async (record, context) => {
    // Create profile
    await context.db.profiles.create({
      user_id: record.id,
      display_name: record.name
    });

    // Send welcome email
    await context.services.email.send({
      to: record.email,
      template: 'welcome-email',
      data: { name: record.name }
    });
  }
};

Common Patterns

Audit Logging

typescript
const auditableEntities = ['orders', 'products', 'users'];

for (const entity of auditableEntities) {
  for (const event of ['after_create', 'after_update', 'after_delete']) {
    registerTrigger({
      entity,
      event,
      handler: async (record, context, oldRecord) => {
        await context.db.audit_logs.create({
          entity_name: entity,
          record_id: record.id,
          action: event.replace('after_', ''),
          old_values: event === 'after_update' ? oldRecord : null,
          new_values: event !== 'after_delete' ? record : null,
          changed_by: context.user.id,
          timestamp: new Date()
        });
      }
    });
  }
}

Cache Invalidation

typescript
const cacheInvalidationTrigger: TriggerDefinition = {
  entity: 'products',
  event: 'after_update',
  name: 'Invalidate Product Cache',

  handler: async (record, context) => {
    await context.cache.delete(`product:${record.id}`);
    await context.cache.delete(`category:${record.category_id}:products`);
    await context.cache.deletePattern('search:products:*');
  }
};

Best Practices

Do's

  • Keep triggers focused and single-purpose
  • Use async triggers for heavy processing
  • Handle errors gracefully
  • Log important actions
  • Use conditions to filter when triggers run
  • Test triggers thoroughly

Don'ts

  • Don't create circular triggers
  • Don't make slow API calls in sync triggers
  • Don't modify the triggering record in after triggers
  • Don't rely on trigger order for critical logic
  • Don't skip error handling