Skip to main content
Write data from a workflow output table to your app’s database:
{
  persistToDatabase: {
    appId: "{{var.appId}}",
    tableName: "Product",
    sourceTable: "products",
    mode: "upsert",
    upsertKey: ["id"],
    fieldMapping: {
      id: "id",
      title: "title",
      vendor: "vendor",
      category: "category",
      createdAt: "createdAt",
      updatedAt: "updatedAt",
    },
  },
}

Configuration

FieldRequiredDescription
appIdYesApp identifier (typically "{{var.appId}}")
tableNameYesTarget table in app database
sourceTableYesWorkflow table from a previous step
modeYesWrite strategy: replaceAll, append, or upsert
fieldMappingYesMaps target database columns to source table columns. Supports generated values.
upsertKeyConditionalRequired when mode is upsert — columns that form the unique constraint
replaceWhereConditionalRequired when mode is replaceAll — scopes the delete operation
onRowErrorNo"fail" (default) or "skip"

Write modes

upsert

Insert new rows, update existing ones based on upsertKey:
{
  mode: "upsert",
  upsertKey: ["id"],
}
The upsertKey must match a unique constraint on the target table.

replaceAll

Atomically delete matching rows, then insert all source rows:
{
  mode: "replaceAll",
  replaceWhere: {
    matchColumns: ["orgId"],
  },
}
replaceWhere scopes the DELETE to rows matching values from the source data.

append

Insert all rows without checking for duplicates:
{
  mode: "append",
}

Validation

Check
appId, tableName, sourceTable, mode, fieldMapping are required
sourceTable exists in previous steps
fieldMapping keys exist in target schema
upsertKey is required when mode is upsert
replaceWhere.matchColumns exist in fieldMapping
Target table exists in app database
All required target columns are mapped
upsertKey has a corresponding unique constraint on the target table
Source and target column types are compatible
For user-triggered jobs, replaceAll mode requires replaceWhere to scope deletes