Skip to main content
The Create or update record block (Records) matches on a unique attribute, updates the record if found, or creates one if not. This is the upsert step for records. Upsert means update if a record already exists, or insert a new one if it does not. The block reuses the existing record instead of adding another. So a webhook or trigger that fires twice for the same person or company produces one record, not two. The match works only if the attribute you match on is truly unique to one record. Good choices are email_address for a person or domains for a company. If you match on something that several records share, the block can overwrite the wrong one.

Inputs

Outputs

Reference the resulting record’s ID in a later block as {{ steps.create_or_update_record.record_id }}.

Behavior

The block reads the matching attribute first, then decides whether to update or create. If exactly one record has the same value on the matching attribute, the block updates that record. If no record matches, the block creates a new one and fills it from the Attributes to set input. The output looks the same in both cases. A downstream block does not need to know which branch ran. Single-value attributes always overwrite. Writing a new email or stage replaces the previous value no matter how Replace existing values is set. That toggle only affects multi-value attributes. Multi-value attributes follow the Replace existing values toggle. With the toggle off, the block adds the new values to whatever is already on the record. With the toggle on, the block throws away the existing values and writes only the new set. This toggle is the single most common cause of unexpected data loss with this block. Turning it on for a tags or categories attribute deletes every value the block did not explicitly include. The block writes on every run. It does not deduplicate beyond the single matching attribute. A record that matches on email still updates even if its other attributes differ.

Gotchas

  • The wrong record gets overwritten. A non-unique matching attribute, such as a first name or a company stage, can match several records. The block then updates one of them instead of the one you meant. Match on an attribute that is unique per record, such as email_address or domains.
  • Multi-select values disappear. Turning on Replace existing values for a multi-value attribute deletes every existing value the run does not re-supply. Leave the toggle off to append. Turn it on only when you mean to replace the full set.
  • The block updates with stale data. Reading from the trigger payload after an earlier block has already changed the record writes outdated values. Reference the output of the block that made the change, not the original trigger data.
  • The run fails on a write without access. A workflow has no write access to objects by default, so the block errors until you grant the workflow write access to the target object. Grant access before you publish.

Examples

Upserting an inbound person by email

A webhook lead-intake workflow receives a form submission. It needs to create the person once, then update them on every later submission. The first submission from priya@acme.com creates the person record. A second submission with an updated job title finds the same record by email and updates it in place. The workspace keeps one Priya Sharma record.

Appending a source tag without losing existing tags

A routing workflow tags inbound people with the channel they arrived on. It keeps the tags they already carry.
A person who already has ["Newsletter"] on lead_source ends up with ["Newsletter", "Webinar"]. The toggle is off, so the block appends rather than replaces.

Resetting a multi-select to a single value

A cleanup workflow needs the lifecycle_stage tags on a company to reflect exactly one current state and to drop the rest. The company matched on acme.com keeps only Customer on lifecycle_stage. Any earlier values, such as Prospect or Trial, are removed.

Credit cost worked example

The block costs 1 credit per run. You pay it whether the block creates a record or updates one. A webhook lead-intake workflow that upserts 800 inbound people a month spends 800 credits on this block. Triggers, conditions, and lookups in the same workflow are free, so the upsert is the only paid step in a typical intake flow. Compare that monthly total against your plan’s allowance on Credits & pricing explained.

Source

Attio Workflows block library. Last reviewed against the Attio Help Center, June 2026.

See also