Skip to main content

Tables

Table Tables let you store structured data in your workspace. You can use them from the UI or from core.table.* actions in a workflow definition. Use tables when you want to:
  • Keep durable records across workflow runs
  • Look up known values such as users, hosts, or indicators
  • Search and export structured data for investigation or reporting
  • Reuse the same dataset across multiple workflows

Columns

Each table has a schema that defines its columns. Choose column types based on the data you want to store and query. You can create tables with the following column types:
  • TEXT
  • INTEGER
  • BOOLEAN
  • NUMERIC
  • JSONB
  • TIMESTAMPTZ
  • UUID
Use TEXT, INTEGER, BOOLEAN, and NUMERIC for simple fields. Use JSONB when you need to store nested structured data, and use TIMESTAMPTZ or UUID for timestamps and identifiers.

Rows

Rows hold the actual records in a table. You can insert, update, delete, look up, and search rows as your workflows process new events. This works well for data such as:
  • Asset inventories
  • User allowlists
  • Enrichment results
  • Investigation evidence
  • External system references
If you already know the field and value you want, use core.table.lookup. If you need broader filtering or text search, use core.table.search_rows. For example, use core.table.lookup when you know the exact value:
- ref: lookup_asset
  action: core.table.lookup
  args:
    table: asset_inventory
    column: hostname
    value: ${{ TRIGGER.hostname }}
For example, use core.table.search_rows when you want to search across rows:
- ref: search_assets
  action: core.table.search_rows
  args:
    table: asset_inventory
    search_term: production
    limit: 25

Index and upsert

You’ll often need to deduplicate data or require all values in a column to be unique. You can do that by creating an index and then using core.table.insert_row with upsert: true. Create unique index For example:
  • One row per hostname
  • One row per email address
  • One row per alert ID
  • One row per hash value
A unique index enforces that rule, and core.table.insert_row with upsert: true updates the existing row instead of creating a duplicate.

Table actions

Use core.table.* actions when you want your workflows to work with tables directly.
  • Tables to create tables, inspect metadata, insert rows, search rows, and export data
  • Use core.table.insert_row with upsert: true when you want to update an existing row that matches a unique index
For example:
- ref: ensure_inventory_table
  action: core.table.create_table
  args:
    name: asset_inventory
    columns:
      - name: hostname
        type: text
      - name: owner
        type: text
    raise_on_duplicate: false
- ref: upsert_asset
  action: core.table.insert_row
  args:
    table: asset_inventory
    upsert: true
    row_data:
      hostname: ${{ TRIGGER.hostname }}
      owner: ${{ TRIGGER.owner }}
- ref: lookup_asset
  action: core.table.lookup
  args:
    table: asset_inventory
    column: hostname
    value: ${{ TRIGGER.hostname }}
For example, this upserts one row per alert ID:
- ref: upsert_alert
  action: core.table.insert_row
  args:
    table: alerts
    upsert: true
    row_data:
      alert_id: ${{ TRIGGER.alert_id }}
      status: ${{ TRIGGER.status }}
      severity: ${{ TRIGGER.severity }}