Browse documentation
Guide Updated 11 August 2026

Persist workflow data

Map an incoming payload onto a data model field by field, save the result to the warehouse, and keep every version of every record.

View as Markdown

Map to Data Model is the step that turns a payload into a record. Whatever the steps above it produced goes in; a row shaped like one of your data models comes out and is saved to the warehouse.

It is the only step type that writes to the warehouse. Everything else in a workflow moves data around; this is where data lands and stays.

Outcome

Every run of the workflow leaves a record behind, and that record's history grows rather than being overwritten.

Before you start

  • A data model with a primary key. See Define a data model.
  • An upstream step that has been tested or sampled, or the left column of the mapping panel will be empty.

1. Add the step

In the builder, open the step palette and pick Map to Data Model. Its node sits on the canvas reading Select data model… until you choose one.

Select the node and the inspector shows a Data Model picker, a Field Mappings divider with an {n} of {n} mapped counter, and a button labelled Map to your model's name. The node itself carries the same counter as a badge, so you can see at a glance which mapping steps are unfinished.

Checkpoint: the node shows your model's name instead of Select data model….

2. Map the fields

Press the Map to button. The panel has two columns.

Available fields on the left is everything upstream: one group per source, each field shown as source.field with its type and whether it is nullable. Destination on the right is your data model's fields, each showing its type, a PK badge on the primary key, and a red asterisk on anything required.

Mapping is click-then-click, not drag-and-drop. Click a field on the left to arm it, then click the destination row you want it to fill. Click the armed item again to disarm it. Hovering a field traces its connection across the middle lane, which is how you check an existing mapping without opening anything.

An unmapped destination row says unmapped in italics and draws a dashed border. While something is armed the same row says click to connect.

Each mapped row gets a small badge naming where its value comes from: the source slug for a plain field reference, static for a literal you typed, var for a computed value, and fx for anything else.

The search box filters every upstream field at once, and the chips above it narrow to one source, or to Vars.

Checkpoint: the counter reads n of n mapped, and the primary key row is one of them.

3. Save and activate

Close the panel and press Save. Mappings are stored with the version.

Activation then checks the work: every required field mapped, the primary key mapped, and the model still holding a primary key at all. See Activation errors.

Verify the result

  • After the next run, Warehouse → your model lists at least one record.
  • Opening a record shows its Change history — every version ever saved, with a date picker to scrub back.
  • A second run for the same primary key adds an entry rather than replacing the first.

What a mapping can be

A mapping is one destination field plus one expression. Three shapes cover almost everything:

  • A field reference. orders.total copies a value across unchanged. This is what clicking a left-column field produces.
  • A static value. 'shopify' or 0 or true writes a constant on every record. Useful for tagging where a record came from.
  • A formula. Anything computed: input.price * 1.2, input.first_name + ' ' + input.last_name, ROUND(input.price * 1.0825, 2).

Every required field has to be mapped, and so does the primary key, before the workflow can be activated.

Computed values

A formula you need twice should not be written twice. The left column has a Formulas group at the top, and + New formula opens the formula builder.

A formula has a name, a value type — string, integer, float, decimal, boolean, datetime, date, map, or array — and an expression. Once saved, reference it from any destination field as vars.your_name, as many times as you like. The list shows a use count beside each one, and renaming a formula repoints every field that referenced it.

Formulas can read upstream fields and other formulas. A reference cycle between two formulas is rejected.

The builder gives you two picklists to compose from. Fields lists your upstream fields grouped by source, plus your other formulas. Operators is grouped into Functions, Logical, Comparison, and Mathematical:

Group Available
Functions IF if / then / else · COALESCE first non-empty · ROUND round a number · LENGTH list / string length · EVERY all items match · SOME any item matches · AT element at index · FIRST first element · LAST last element
Logical AND all true · OR any true · NOT negate · || fallback / or-else
Comparison == · != · > · < · >= · <=
Mathematical + add / concatenate · - subtract · * multiply · / divide

Validate checks the expression against the real engine rather than a client-side approximation, and Save formula stays disabled until it passes. Errors are specific: an empty formula, an invalid expression, a name that is already taken, or a name that breaks the letters-numbers-underscore rule.

What the warehouse keeps

Each run of the step saves one record: the mapped values, the data model they belong to, and a pointer back to the workflow version and step that produced them. Three properties of that store are worth knowing, because the rest of the product is built on them.

Nothing is ever overwritten. A second write for the same primary key does not replace the first — it becomes the next entry in that entity's history. Open Warehouse, pick a data model, and click an entity to get its Change history: every version that was ever saved, with a date picker to scrub back and see the entity as it stood at an earlier moment. The timeline is complete by construction, because nothing is updated and nothing is deleted.

Every record knows where it came from. Because each one carries the workflow version and step that produced it, "where did this number come from?" is a question with an answer rather than an investigation. Workflows → Monitor holds the other half of that trail: what each step of each run did, recorded as it happened. That same running commentary is how an interrupted run picks up where it left off instead of repeating work that already succeeded.

Dashboards read these records directly. A widget names a data model, a field, an aggregation, and a time range, and Hodoflow computes it — no query language involved. Records are time-stamped with when the thing happened, so time is a first-class filter rather than an afterthought: the same widget can show the last hour, yesterday, or the year to date with nothing recomputed upstream. And because each new record is broadcast as it is saved, widgets update on screen as data lands instead of waiting for a refresh.

Because every source is mapped onto the same data models, data from three different systems ends up genuinely comparable. Defining the shape once is what does that.

The whole path, in one line each:

  1. Something arrives from outside, or a workflow goes and fetches it.
  2. A trigger starts a run.
  3. Steps fetch, transform, and branch, each outcome recorded as it happens.
  4. Map to Data Model maps the result onto a data model.
  5. A record is saved, and that entity's history grows by one version.
  6. Every dashboard watching that data model updates.

Common problems

The left column is empty. Nothing upstream has been sampled yet. Sample a press Test Request on an HTTP step, and the fields appear. See Configure and test a step.

The canvas says Select a data model, No field mappings configured, or Primary key field must be mapped. Those are the three ways this step can be incomplete, and each blocks activation.

A drift banner appeared. A source's configuration changed since it was last sampled. Existing mappings still save, but this workflow can't be activated until you re-sample. Each affected source gets its own Re-sample button. Mappings keep saving throughout — it is only activation that is gated, so you never lose work to drift.

A formula will not save. Validate runs it against the real engine. The error names the problem: an empty formula, an invalid expression, a duplicate name, or a name with characters other than letters, numbers, and underscores.

Records are not appearing. Check the run completed in Monitor. A run that failed before reaching this step wrote nothing.

I expected an update and got a second record. That is the design. The history is append-only; the latest entry is what dashboards read by default.

Next step

Build a dashboard — read the records back out.

Related documentation