> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xano.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XanoScript for Triggers

> Define database, workspace, realtime, and MCP server triggers using XanoScript

export const xanoscriptApiInputsDiagram = `
\`\`\`mermaid
flowchart TB
    A[Declaration] --> B[Input]
    B --> C[Stack]
    C --> D[Response]
    D --> E[Settings]
    style A fill:#cdeaff,stroke:#0077cc,stroke-width:2px
    style B fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style C fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style D fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style E fill:#f5f5f5,stroke:#ccc,stroke-width:1px
\`\`\`
`;

export function SideBySide({diagram, children}) {
  return <div style={{
    display: "flex",
    gap: "1rem",
    alignItems: "flex-start",
    flexWrap: "wrap"
  }}>
      <div style={{
    flex: "0 0 180px",
    minWidth: "150px"
  }}>
        <div>{mdx(diagram)}</div>
      </div>
      <div style={{
    flex: 1
  }}>
        {children}
      </div>
    </div>;
}

export const HoverImageCode = ({src, alt = "", width = "100%", maxWidth = "800px", className = "", defaultOpen = false, openOnHover = true, children}) => {
  const [open, setOpen] = useState(defaultOpen);
  const panelRef = useRef(null);
  const [maxHeight, setMaxHeight] = useState(0);
  useEffect(() => {
    if (panelRef.current) {
      setMaxHeight(open ? panelRef.current.scrollHeight : 0);
    }
  }, [open, children]);
  const handleMouseEnter = () => openOnHover && setOpen(true);
  const handleMouseLeave = () => openOnHover && setOpen(false);
  const handleClick = () => setOpen(s => !s);
  const handleImageClick = e => {
    e.stopPropagation();
    e.preventDefault();
    handleClick();
  };
  const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  const transition = prefersReducedMotion ? "none" : "max-height 300ms ease, opacity 300ms ease, transform 300ms ease";
  return <div className={`border rounded-md overflow-hidden ${className}`} style={{
    width,
    maxWidth
  }} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
      {}
      <div role="button" tabIndex={0} aria-label="Toggle code" aria-expanded={open} style={{
    cursor: "pointer"
  }}>
        <img src={src} alt={alt} onClickCapture={e => {
    e.stopPropagation();
    e.preventDefault();
    handleClick();
  }} style={{
    display: "block",
    width: "100%",
    height: "auto"
  }} />
      </div>

      {}
      <div className="not-prose" ref={panelRef} style={{
    overflow: "hidden",
    maxHeight: `${maxHeight}px`,
    opacity: open ? 1 : 0,
    transform: open ? "translateY(0)" : "translateY(-6px)",
    transition
  }}>
        <div style={{
    padding: "0.75rem"
  }}>{children}</div>
      </div>
    </div>;
};

## Introduction

Triggers in XanoScript allow you to define automated responses to specific events across your application. Unlike other primitives, triggers come in several different types, each responding to different kinds of events.

XanoScript supports four types of triggers:

* **Database triggers** — Respond to table changes (insert, update, delete)
* **Workspace triggers** — Respond to workspace events (branch changes, deployments)
* **Realtime triggers** — Respond to realtime channel events (messages, joins)
* **MCP server triggers** — Respond to MCP server connection events

Each trigger type has its own unique structure and input schema, but they all follow a similar pattern of declaration, input, stack, and response.

***

## Anatomy

Every XanoScript trigger follows a predictable structure, though the specific components vary by trigger type.

Here's a quick visual overview of the main building blocks — from **declaration** at the top to **settings** at the bottom.<br /><br />You can find more detail about each section by continuing below.

```mermaid theme={null}
flowchart LR
    A[Declaration] --> B[Input] --> C[Stack] --> D[Response] --> E[Settings]
    style A fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style B fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style C fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style D fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style E fill:#f5f5f5,stroke:#ccc,stroke-width:1px
```

### Declaration

Every trigger starts with a **declarative header** that specifies its type, name, and trigger-specific configuration.

<div style={{ display: "flex", gap: "1rem", alignItems: "flex-start", flexWrap: "wrap" }}>
  <div style={{ flex: "0 0 180px", minWidth: "150px" }}>
    <div>
      ```mermaid theme={null}
      flowchart TB
      A[Declaration] --> B[Input]
      B --> C[Stack]
      C --> D[Response]
      D --> E[Settings]
      style A fill:#cdeaff,stroke:#0077cc,stroke-width:2px
      style B fill:#f5f5f5,stroke:#ccc,stroke-width:1px
      style C fill:#f5f5f5,stroke:#ccc,stroke-width:1px
      style D fill:#f5f5f5,stroke:#ccc,stroke-width:1px
      style E fill:#f5f5f5,stroke:#ccc,stroke-width:1px
      ```
    </div>
  </div>

  <div style={{ flex: 1 }}>
    ```java XanoScript lines icon="code" theme={null}
    // <what this trigger does>
    <table_trigger|workspace_trigger|realtime_trigger|mcp_server_trigger> <trigger_name> {
      <trigger_specific_config>
      ...
    }
    ```

    | Element                   | Required | Description                                                                        |
    | ------------------------- | -------- | ---------------------------------------------------------------------------------- |
    | `trigger_type`            | ✅        | Declares the trigger primitive type.                                               |
    | `trigger_name`            | ✅        | The unique name for the trigger.                                                   |
    | `description`             | no       | A short summary of the trigger. May also appear as a “//” comment above the block. |
    | `trigger_specific_config` | varies   | Configuration specific to the trigger type (table, channel, mcp\_server, etc.).    |
  </div>
</div>

***

## Trigger Types

### Database Triggers

Database triggers respond to changes in database tables. They can be configured to fire on insert, update, delete, or truncate operations.

```java XanoScript lines icon="code" theme={null}
// Sends an email when a user signs up for the service.
table_trigger send_email_on_signup {
  table = "user"
  ...
}
```

**Database Trigger Configuration:**

* `table` — The table name to monitor for changes
* `actions` — Specifies which database operations trigger the event

### Workspace Triggers

Workspace triggers respond to workspace-level events like branch changes, deployments, and other administrative actions.

```java XanoScript lines icon="code" theme={null}
// Sends an email to the admin on branch activities
workspace_trigger notify_on_branch_change {
  ...
}
```

**Workspace Trigger Configuration:**

* `actions` — Specifies which workspace events trigger the action

### Realtime Triggers

Realtime triggers respond to events in realtime channels, such as messages or user joins.

```java XanoScript lines icon="code" theme={null}
// Logs any realtime activity
realtime_trigger on_event {
  channel = "my_channel"
  ...
}
```

**Realtime Trigger Configuration:**

* `channel` — The realtime channel to monitor
* `actions` — Specifies which realtime events trigger the action

### MCP Server Triggers

MCP server triggers respond to MCP server connection events and can modify the toolset and tools available to the server.

```java XanoScript lines icon="code" theme={null}
mcp_server_trigger on_connect_action {
  mcp_server = "My MCP Server"
  ...
}
```

**MCP Server Trigger Configuration:**

* `mcp_server` — The MCP server name to monitor
* `actions` — Specifies which MCP events trigger the action

***

### Section 1: Input

The `input` block defines the data that will be available to the trigger. Each trigger type has its own specific input schema.

<div style={{ display: "flex", gap: "1rem", alignItems: "flex-start", flexWrap: "wrap" }}>
  <div className="stickyDiagram">
    ```mermaid theme={null}
    flowchart TB
    A[Declaration] --> B[Input]
    B --> C[Stack]
    C --> D[Response]
    D --> E[Settings]
    style A fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style B fill:#cdeaff,stroke:#0077cc,stroke-width:2px
    style C fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style D fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style E fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    ```
  </div>

  <div style={{ flex: 1 }}>
    **Database Trigger Input:**

    ```java XanoScript lines icon="code" theme={null}
    input {
      json new
      json old
      enum action {
        values = ["insert", "update", "delete", "truncate"]
      }
      text datasource
    }
    ```

    **Workspace Trigger Input:**

    ```java XanoScript lines icon="code" theme={null}
    input {
      object to_branch {
        schema {
          int id
          text label
        }
      }
      object from_branch {
        schema {
          int id
          text label
        }
      }
      enum action {
        values = ["branch_live", "branch_merge", "branch_new"]
      }
    }
    ```

    **Realtime Trigger Input:**

    ```java XanoScript lines icon="code" theme={null}
    input {
      enum action {
        values = ["message", "join"]
      }
      text channel
      object client {
        schema {
          json extras
          object permissions {
            schema {
              int dbo_id
              text row_id
            }
          }
        }
      }
      object options {
        schema {
          bool authenticated
          text channel
        }
      }
      json payload
    }
    ```

    **MCP Server Trigger Input:**

    ```java XanoScript lines icon="code" theme={null}
    input {
      object toolset {
        schema {
          int id
          text name
          text instructions
        }
      }
      object[] tools {
        schema {
          int id
          text name
          text instructions
        }
      }
    }
    ```

    Each trigger type provides different input data based on the event that triggered it. The input schema is automatically provided by Xano based on the trigger type.
  </div>
</div>

***

### Section 2: Stack

The `stack` block contains the actual logic that will be executed when the trigger fires.

<div style={{ display: "flex", gap: "1rem", alignItems: "flex-start", flexWrap: "wrap" }}>
  <div className="stickyDiagram">
    ```mermaid theme={null}
    flowchart TB
    A[Declaration] --> B[Input]
    B --> C[Stack]
    C --> D[Response]
    D --> E[Settings]
    style A fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style C fill:#cdeaff,stroke:#0077cc,stroke-width:2px
    style B fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style D fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style E fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    ```
  </div>

  <div style={{ flex: 1 }}>
    ```java XanoScript lines icon="code" theme={null}
    stack {
      util.send_email {
        api_key = ""
        service_provider = "xano"
        subject = "Welcome"
        message = "Thanks for signing up, "|concat:($input.new.name|split:" "|first):""
        bcc = []
        cc = []
        from = ""
        reply_to = ""
        scheduled_at = ""
      } as $email_sent
    }
    ```

    The stack works exactly like other XanoScript primitives:

    * Functions are called with their parameters
    * Variables can be created and manipulated
    * Conditional logic can be applied
    * Database operations can be performed

    The main difference is that triggers have access to the specific input data provided by the triggering event.
  </div>
</div>

***

### Section 3: Response

The `response` block defines what data your trigger returns (if any). Not all trigger types require a response.

<div style={{ display: "flex", gap: "1rem", alignItems: "flex-start", flexWrap: "wrap" }}>
  <div className="stickyDiagram">
    ```mermaid theme={null}
    flowchart TB
    A[Declaration] --> B[Input]
    B --> C[Stack]
    C --> D[Response]
    D --> E[Settings]
    style A fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style D fill:#cdeaff,stroke:#0077cc,stroke-width:2px
    style B fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style C fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style E fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    ```
  </div>

  <div style={{ flex: 1 }}>
    **MCP Server Trigger Response:**

    ```java XanoScript lines icon="code" theme={null}
    response = {toolset: $var.toolset, tools: $tools}
    ```

    **Realtime Trigger Response:**

    ```java XanoScript lines icon="code" theme={null}
    response = $input.payload
    ```

    * **Database triggers** typically don't need responses
    * **Workspace triggers** typically don't need responses
    * **Realtime triggers** can return data to the channel
    * **MCP server triggers** must return modified toolset and tools
  </div>
</div>

***

## Settings

Trigger primitives support several optional settings that control which events trigger the action and how the trigger is organized.

<div style={{ display: "flex", gap: "0rem", alignItems: "flex-start", flexWrap: "wrap" }}>
  <div className="stickyDiagram">
    ```mermaid theme={null}
    flowchart TB
    A[Declaration] --> B[Input]
    B --> C[Stack]
    C --> D[Response]
    D --> E[Settings]
    style A fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style E fill:#cdeaff,stroke:#0077cc,stroke-width:2px
    style B fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style C fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    style D fill:#f5f5f5,stroke:#ccc,stroke-width:1px
    ```
  </div>

  <div style={{ flex: 1 }}>
    | Setting   | Type           | Required | Description                                                                          |
    | --------- | -------------- | -------- | ------------------------------------------------------------------------------------ |
    | `actions` | object         | ✅        | Specifies which events trigger the action. Keys are event names, values are boolean. |
    | `tags`    | array\[string] | no       | A list of tags used to categorize and organize the trigger in your workspace.        |

    **Actions Configuration Examples:**

    **Database Trigger Actions:**

    ```java XanoScript lines icon="code" theme={null}
    actions = {insert: true, update: false, delete: false, truncate: false}
    ```

    **Workspace Trigger Actions:**

    ```java XanoScript lines icon="code" theme={null}
    actions = {branch_live: true, branch_merge: true, branch_new: true}
    ```

    **Realtime Trigger Actions:**

    ```java XanoScript lines icon="code" theme={null}
    actions = {message: true, join: true}
    ```

    **MCP Server Trigger Actions:**

    ```java XanoScript lines icon="code" theme={null}
    actions = {connection: true}
    ```
  </div>
</div>

***

## Detailed Examples

### Database Trigger Example

```java XanoScript lines icon="code" theme={null}
// Sends an email when a user signs up for the service.
table_trigger send_email_on_signup {
  table = "user"
  input {
    json new
    json old
    enum action {
      values = ["insert", "update", "delete", "truncate"]
    }
    text datasource
  }

  stack {
    util.send_email {
      api_key = ""
      service_provider = "xano"
      subject = "Welcome"
      message = "Thanks for signing up, "|concat:($input.new.name|split:" "|first):""
      bcc = []
      cc = []
      from = ""
      reply_to = ""
      scheduled_at = ""
    } as $email_sent
  }

  tags = ["user actions"]
  actions = {insert: true}
}
```

### MCP Server Trigger Example

```java XanoScript lines icon="code" theme={null}
mcp_server_trigger on_connect_action {
  mcp_server = "My MCP Server"
  input {
    object toolset {
      schema {
        int id
        text name
        text instructions
      }
    }

    object[] tools {
      schema {
        int id
        text name
        text instructions
      }
    }
  }

  stack {
    var $toolset {
      value = $input.toolset
    }
  
    var $tools {
      value = $input.tools
    }
  
    db.get user {
      field_name = "id"
      field_value = $auth.id
    } as $user1
  
    conditional {
      if ($user1.admin == false) {
        var.update $toolset {
          value = ""
        }

        var.update $tools {
          value = ""
        }
      }
    }
  }

  response {
    value = {toolset: $var.toolset, tools: $tools}
  }

  actions = {connection: true}
}
```

### Workspace Trigger Example

```java XanoScript lines icon="code" theme={null}
// Sends an email to the admin on branch activities.
workspace_trigger notify_on_branch_change {
  input {
    object to_branch {
      schema {
        int id
        text label
      }
    }
  
    object from_branch {
      schema {
        int id
        text label
      }
    }
  
    enum action {
      values = ["branch_live", "branch_merge", "branch_new"]
    }
  }

  stack {
    util.send_email {
      api_key = ""
      service_provider = "xano"
      subject = "Branch activity has occurred"
      message = $input.action
      bcc = []
      cc = []
      from = ""
      reply_to = ""
      scheduled_at = ""
    } as $x1
  }

  actions = {branch_live: true, branch_merge: true, branch_new: true}
}
```

### Realtime Trigger Example

```java XanoScript lines icon="code" theme={null}
// Logs any realtime activity.
realtime_trigger on_event {
  channel = "my_channel"
  input {
    enum action {
      values = ["message", "join"]
    }

    text channel
    object client {
      schema {
        json extras
        object permissions {
          schema {
            int dbo_id
            text row_id
          }
        }
      }
    }

    object options {
      schema {
        bool authenticated
        text channel
      }
    }

    json payload
  }

  stack {
    db.add log {
      data = {
        created_at   : "now"
        user_message : ""
        agent_message: ""
        why          : ""
        payload      : $input.payload
      }
    } as $log1
  }

  response = $input.payload
  actions = {message: true, join: true}
}
```

***

## What's Next

Now that you understand how to define triggers in XanoScript, here are a few great next steps:

<Card title="Explore the function reference" icon="function" horizontal href="/xanoscript/function-reference">
  Learn about the built-in functions available in the stack to start writing more complex trigger logic.
</Card>

<Card title="Try it out in VS Code" icon="https://mintcdn.com/xano-997cb9ee/aZQYcxhIvSDTNEim/images/icons/vscode.svg?fit=max&auto=format&n=aZQYcxhIvSDTNEim&q=85&s=bb6c91058fcbe6ee28fcda04e03de2e6" horizontal href="/xanoscript/vs-code" width="100" height="100" data-path="images/icons/vscode.svg">
  Use the XanoScript VS Code extension with Copilot to write XanoScript in your favorite IDE.
</Card>

<Card title="Learn about APIs" icon="cube" horizontal href="/xanoscript/api">
  Create APIs that can be called by your triggers to build complete automated workflows.
</Card>
