> For the complete documentation index, see [llms.txt](https://docs.flosum.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flosum.com/data-migrator/templates/migration/how-record-mapping-works.md).

# How Record Mapping Works

## ![](https://2769999621-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvaxzColPOlNbsq4imqpd%2Fuploads%2FcfMTqg4Brbm9baWutclZ%2FSummary2-Small-Icon.svg?alt=media\&token=d1cf162d-c02d-4184-988e-7f7350e450fc) Overview

Data Migrator uses record mapping to keep records accurate across multiple migration runs. When you enable record mapping for an object, Data Migrator maps individual records between the source and target organizations so that subsequent migrations add only new records and update existing ones. You control record mapping individually for each object in a template. Data Migrator provides two methods for mapping records between the source and target organizations: **Automatic** and **Manual**. The following sections describe how each method works and include example scenarios that illustrate successful and failed record mapping.

* [#automatic-record-mapping](#automatic-record-mapping "mention")
* [#manual-record-mapping](#manual-record-mapping "mention")
* [#record-mapping-scenarios](#record-mapping-scenarios "mention")

{% hint style="info" %}

#### Enabling Record Mapping

By default, record mapping is disabled for all objects in a template. Without record mapping enabled, all source records are always inserted into the target organization during migration. This can result in duplicates if the same record exists in both locations.

Record mapping for an object is enabled from its Settings tab. The following article describes how to enable record mapping for an object.

* [Setting Object Record Mapping](/data-migrator/templates/template-designer/setting-object-record-mapping.md)
  {% endhint %}

## Automatic Record Mapping

Automatic record mapping is a stateful, mapping-based strategy that uses an internal mapping table to link source and target records. It relies on historical mappings from past deployments rather than real-time target data. Once a source-to-target mapping exists, the relationship is fixed, so there is no ambiguity for records already migrated using Automatic.

Automatic is designed for repeat migrations when:

* Data Migrator is the only migration tool in use
* The target org is empty during the first migration
* Long-term consistency across runs is required

Automatic guarantees that:

* The same source record always updates the same mapped target record
* Changes in business fields don't affect record matching
* Record updates are deterministic once a mapping exists

However, Automatic doesn't evaluate real-time target data.

### How Automatic Works

Automatic follows a deterministic, mapping-driven process. The diagram below illustrates the full flow.

<figure><img src="https://2769999621-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvaxzColPOlNbsq4imqpd%2Fuploads%2FHQ3R5paTJEYcCDt5ZNZi%2FFlosum%20Data%20Migrator%20VEID%20Flow.png?alt=media&amp;token=e9ff49d1-056a-490d-940a-b979f06cfd64" alt=""><figcaption></figcaption></figure>

{% stepper %}
{% step %}

#### Read Source Record

Each source record is processed individually during the migration run.
{% endstep %}

{% step %}

#### Look Up Mapping in the Database

The system checks whether a mapping already exists for the source record's ID.
{% endstep %}

{% step %}

#### Evaluate the Mapping Result

<table><thead><tr><th width="180.33331298828125">Mapping Found</th><th>Action</th></tr></thead><tbody><tr><td>No</td><td>INSERT a new record in the target org.</td></tr><tr><td>Yes</td><td>UPDATE the existing mapped target record.</td></tr></tbody></table>
{% endstep %}

{% step %}

#### Save the Mapping

When no mapping exists, the system inserts the record into the target org and creates a new mapping. On subsequent migrations, this record is updated rather than inserted again. This process repeats with each run, so newly added source records are tracked in the database.
{% endstep %}
{% endstepper %}

### Limitations

{% hint style="warning" %}

#### Important Limitations of Automatic Record Mapping

* Automatic cannot map records that already exist in the target organization.
* If another tool or manual process creates or modifies records in the target org, Automatic mappings can become outdated, leading to duplicate records.
* Automatic can only track records migrated through Data Migrator.
  {% endhint %}

#### Outdated Mapping

Automatic is only as reliable as its database. Mappings become outdated when records are created in the target org, either manually or via another tool. The example below shows how this leads to duplicate records.

**Example:**

1. A user runs a migration for all Contact records to an empty org.
   1. All Contact records are copied from the source to the target org.
   2. Automatic mappings are created for each record.
2. The user manually creates Contact records for **Charlie** and **Alice** in both the source and target orgs.
3. The user runs another migration for all Contact records from the source org to the target org.
   1. **Charlie** and **Alice** have no Automatic mapping because they weren't migrated before.
   2. New records for **Charlie** and **Alice** are created in the target org.
   3. The target org now has duplicate records for **Charlie** and **Alice**: one from the manual creation and one from the migration.

## Manual Record Mapping

Manual record mapping combines one or more record fields into a composite ID that links source and target records. Unlike standard Salesforce external IDs, any field can be used in the composite ID. When Manual searches the target org and finds exactly one matching record, it updates that record instead of inserting a new one.

It is designed for migrating records into target orgs that already contain records not previously mapped with Automatic record mapping, or for records in the target org created by other tools. Choose the Manual record mapping fields carefully: if the value of any selected field changes, the mapping will no longer match the previously migrated record.

### How Manual Works

Before using Manual record mapping to migrate records, you must select one or more fields for the object to use for the record mapping. The selected fields are combined to create a key that is both unique and stable. This means the key does not change when commonly updated record fields change, and it is unique for every record in the org. You can choose one or more fields to use in the Manual key. The more fields you select, the more likely the key is to be unique. However, selecting more fields also increases the chance that the key will be unstable.

During Manual record mapping, the process searches the target org for matches against the generated key. The diagram and explanation below illustrate how it works.

<figure><img src="https://2769999621-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvaxzColPOlNbsq4imqpd%2Fuploads%2FSS7vNmCOIbsfbeAEDUTo%2FFlosum%20Data%20Migrator%20CEID%20Flow.png?alt=media&amp;token=2b82cea9-8699-4038-a8ad-e88ed6380754" alt=""><figcaption></figcaption></figure>

{% stepper %}
{% step %}

### Read Source Record

Each source record is processed individually during the migration run.
{% endstep %}

{% step %}

### Generate Key

A **KEY** is generated from the record’s fields selected for the Manual mapping.
{% endstep %}

{% step %}

### Query Target Org

Run a SOQL query in the target org for the **KEY**.
{% endstep %}

{% step %}

### Evaluate the Query Result

<table><thead><tr><th width="219.6666259765625">Number of Records Matched</th><th>Action</th></tr></thead><tbody><tr><td>0</td><td>INSERT a new record in the target org.</td></tr><tr><td>1</td><td>UPDATE the existing matched target record.</td></tr><tr><td>2 or more</td><td>ERROR - the record is skipped. More than one record matches the <strong>KEY</strong>, so the Manual key for this record is not unique, and the record can’t be migrated.</td></tr></tbody></table>
{% endstep %}
{% endstepper %}

### Limitations

{% hint style="warning" %}

#### Important Limitations of Manual Record Mapping

Selecting a combination of stable fields that create a unique ID for each record is critical.

* **Stable**: If a value in one of the fields selected for the key changes, the Manual mapping will no longer match the previously migrated record, and a new record will be inserted, resulting in a duplicate.
* **Unique**: If two or more records share the same key in the source org, the migration cannot correctly map them to target records because the key is not unique.
  {% endhint %}

#### Bad Manual Fields

Manual record mapping is only reliable if the fields chosen for the Manual mapping create a key that is both stable and unique. Below are examples of poor field choices.

The following examples use the Contact object.

<table><thead><tr><th width="220">Fields Selected For Key</th><th>Why these fields are a bad choice</th></tr></thead><tbody><tr><td><code>Name</code> and <code>City</code></td><td>Although <code>Name</code> rarely changes, pairing it with <code>City</code> makes the key unstable, because a contact's city can change.</td></tr><tr><td><code>Title</code> and <code>Department</code></td><td>This combination is not unique: multiple contacts can share the same title and department.</td></tr><tr><td><code>Name</code> and <code>Birthday</code></td><td>This combination appears unique and stable, but <code>Birthday</code> is often empty at first and filled in later, which makes the key unstable.</td></tr></tbody></table>

## Record Mapping Scenarios

{% hint style="success" %}

#### Template Design

Object: **Contact**

* Field: **Name**
* Field: **Email**
* Field: **City**
  {% endhint %}

The tables below show the source and target records, with the differences in bold.

**Source Org Contact Records**

<table><thead><tr><th width="200.3333740234375">ID</th><th>Name</th><th width="210">Email</th><th>City</th></tr></thead><tbody><tr><td>001D000000kL4p1</td><td>Alice</td><td>alice@company.com</td><td><strong>Berlin</strong></td></tr><tr><td>001D000000kL4p2</td><td>Bob</td><td><strong>bobNew@company.com</strong></td><td>London</td></tr><tr><td>001D000000kL4p3</td><td>Charlie</td><td>charlie@company.com</td><td>Paris</td></tr><tr><td>001D000000kL4p4</td><td><strong>Dave</strong></td><td><strong>dave@company.com</strong></td><td><strong>Seattle</strong></td></tr></tbody></table>

**Target Org Contact Records**

<table><thead><tr><th width="200.33331298828125">ID</th><th>Name</th><th width="210">Email</th><th>City</th></tr></thead><tbody><tr><td>002D000000kL5p1</td><td>Alice</td><td>alice@company.com</td><td>New York</td></tr><tr><td>002D000000kL5p2</td><td>Bob</td><td>bob@company.com</td><td>London</td></tr><tr><td>002D000000kL5p3</td><td>Charlie</td><td>charlie@company.com</td><td>Paris</td></tr></tbody></table>

### Data Migration with Automatic Record Mapping

#### Successful Scenario

In this scenario, a previous migration already created an Automatic mapping between the source and target orgs. The table below shows that mapping.

| Source Name | Source ID       | Target ID       |
| ----------- | --------------- | --------------- |
| Alice       | 001D000000kL4p1 | 002D000000kL5p1 |
| Bob         | 001D000000kL4p2 | 002D000000kL5p2 |
| Charlie     | 001D000000kL4p3 | 002D000000kL5p3 |

When the migration runs, Automatic record mapping looks up each source record's ID in the existing mapping. Records with a stored mapping are updated in the target org, and records without a mapping are inserted as new records. The diagram and table below illustrate this process and the resulting actions in the target org.

<figure><img src="https://2769999621-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvaxzColPOlNbsq4imqpd%2Fuploads%2FaIMfSu7i6GDBlAQuOiXT%2F3_VEID%20Record%20Mapping%20Example.png?alt=media&amp;token=0db00575-fe39-412d-972b-ad5857d23307" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="179.66668701171875">ID</th><th>Name</th><th width="210">Email</th><th>City</th><th>Operation</th></tr></thead><tbody><tr><td>002D000000kL5p1</td><td>Alice</td><td>alice@company.com</td><td><strong>Berlin</strong></td><td>UPDATE</td></tr><tr><td>002D000000kL5p2</td><td>Bob</td><td><strong>bobNew@company.com</strong></td><td>London</td><td>UPDATE</td></tr><tr><td>002D000000kL5p3</td><td>Charlie</td><td>charlie@company.com</td><td>Paris</td><td>UPDATE</td></tr><tr><td>002D000000kL5p4</td><td><strong>Dave</strong></td><td><strong>dave@company.com</strong></td><td><strong>Seattle</strong></td><td>INSERT</td></tr></tbody></table>

A new Automatic mapping is then added for the newly inserted record:

| Source Name | Source ID       | Target ID       |
| ----------- | --------------- | --------------- |
| Dave        | 001D000000kL4p4 | 002D000000kL5p4 |

#### Failed Scenario

In this scenario, a previous migration had already created an Automatic mapping between the source and target orgs; however, only two records were mapped at that time. The table below shows that mapping.

| Source Name | Source ID       | Target ID       |
| ----------- | --------------- | --------------- |
| Alice       | 001D000000kL4p1 | 002D000000kL5p1 |
| Bob         | 001D000000kL4p2 | 002D000000kL5p2 |

Before the next migration, an external tool adds a record for Charlie to both the source and target orgs. When the migration runs, Automatic looks up each source record's ID in the existing mapping, updating target records that already have a mapping and inserting new records for those that don't.

The diagram and table below illustrate this process and the resulting actions in the target org. Because no Automatic mapping exists for Charlie, the migration inserts a duplicate record, shown in the additional inserted row.

<figure><img src="https://2769999621-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvaxzColPOlNbsq4imqpd%2Fuploads%2FyGETlsSHDtegUt29M7Lp%2F4_VEID%20Record%20Mapping%20Example%20-%20Failed.png?alt=media&amp;token=b651fbc8-e7d2-4747-be3c-0b9670ce2624" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="180.33331298828125">ID</th><th>Name</th><th width="209.666748046875">Email</th><th>City</th><th>Operation</th></tr></thead><tbody><tr><td>002D000000kL5p1</td><td>Alice</td><td>alice@company.com</td><td><strong>Berlin</strong></td><td>UPDATE</td></tr><tr><td>002D000000kL5p2</td><td>Bob</td><td><strong>bobNew@company.com</strong></td><td>London</td><td>UPDATE</td></tr><tr><td>002D000000kL5p3</td><td>Charlie</td><td>charlie@company.com</td><td>Paris</td><td></td></tr><tr><td><mark style="color:$danger;"><strong>002D000000kL5p4</strong></mark></td><td><mark style="color:$danger;"><strong>Charlie</strong></mark></td><td><mark style="color:$danger;"><strong>charlie@company.com</strong></mark></td><td><mark style="color:$danger;"><strong>Paris</strong></mark></td><td><mark style="color:$danger;"><strong>INSERT</strong></mark></td></tr><tr><td>002D000000kL5p5</td><td><strong>Dave</strong></td><td><strong>dave@company.com</strong></td><td><strong>Seattle</strong></td><td>INSERT</td></tr></tbody></table>

Two new Automatic mappings are added for the newly inserted records:

| Source Name | Source ID       | Target ID       |
| ----------- | --------------- | --------------- |
| Charlie     | 001D000000kL4p3 | 002D000000kL5p4 |
| Dave        | 001D000000kL4p4 | 002D000000kL5p5 |

{% hint style="warning" %}
The migration failed because an external tool added Charlie to both the source and target orgs without creating an Automatic mapping between them. With no mapping for Charlie, Automatic inserted a new record in the target org instead of updating the existing one, resulting in a duplicate.
{% endhint %}

### Data Migration with Manual Record Mapping

#### Successful Scenario

Manual Field Key: `Name`

In this scenario, Manual record mapping matches records using the configured key. With `Name` as the Manual key, the system generates a key for each source record and queries the target org for a match. Records that return exactly one match are updated, and records that return no match are inserted. The diagram and table below illustrate the Manual record-mapping process and the resulting actions in the target org.

<figure><img src="https://2769999621-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvaxzColPOlNbsq4imqpd%2Fuploads%2FeN0MzVUkDxLyb4oaEEok%2F1_CEID%20Record%20Mapping%20Example.png?alt=media&amp;token=6a6b92f2-6cde-457c-90cf-bca80edd8701" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="180.3333740234375">ID</th><th>Name</th><th width="209.6666259765625">Email</th><th>City</th><th>Operation</th></tr></thead><tbody><tr><td>002D000000kL5p1</td><td>Alice</td><td>alice@company.com</td><td><strong>Berlin</strong></td><td>UPDATE</td></tr><tr><td>002D000000kL5p2</td><td>Bob</td><td><strong>bobNew@company.com</strong></td><td>London</td><td>UPDATE</td></tr><tr><td>002D000000kL5p3</td><td>Charlie</td><td>charlie@company.com</td><td>Paris</td><td>UPDATE</td></tr><tr><td>002D000000kL5p4</td><td><strong>Dave</strong></td><td><strong>dave@company.com</strong></td><td><strong>Seattle</strong></td><td>INSERT</td></tr></tbody></table>

#### Failed Scenario

Manual Field Key: `Name` + `Email`

In this scenario, Manual record mapping uses `Name` + `Email` as the configured key. For each source record, the system generates this key and queries the target org for a match. Because Bob's source record has a new value in one of the key fields, it no longer matches his record in the target org.

Records that return exactly one match are updated, and records with no match are inserted. The diagram and explanation below show the Manual record mapping process and the resulting actions in the target org. Since Bob's source key no longer matches his existing target record, the migration inserts a duplicate, shown in the additional inserted row.

<figure><img src="https://2769999621-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FvaxzColPOlNbsq4imqpd%2Fuploads%2FOSRDO54tfxS7GfSUJKvq%2F2_CEID%20Record%20Mapping%20Example%20-%20Failed.png?alt=media&amp;token=f1fdb64e-0820-4337-94c4-cdea43f3633b" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="180.33331298828125">ID</th><th>Name</th><th width="210.3333740234375">Email</th><th>City</th><th>Operation</th></tr></thead><tbody><tr><td>002D000000kL5p1</td><td>Alice</td><td>alice@company.com</td><td><strong>Berlin</strong></td><td>UPDATE</td></tr><tr><td>002D000000kL5p2</td><td>Bob</td><td>bob@company.com</td><td>London</td><td></td></tr><tr><td>002D000000kL5p3</td><td>Charlie</td><td>charlie@company.com</td><td>Paris</td><td>UPDATE</td></tr><tr><td><mark style="color:$danger;"><strong>002D000000kL5p4</strong></mark></td><td><mark style="color:$danger;"><strong>Bob</strong></mark></td><td><mark style="color:$danger;"><strong>bobNew@company.com</strong></mark></td><td><mark style="color:$danger;"><strong>London</strong></mark></td><td><mark style="color:$danger;"><strong>INSERT</strong></mark></td></tr><tr><td>002D000000kL5p5</td><td><strong>Dave</strong></td><td><strong>dave@company.com</strong></td><td><strong>Seattle</strong></td><td>INSERT</td></tr></tbody></table>

{% hint style="warning" %}
The migration failed because Bob's `Email` value changed in the source org after the target record was created. Since `Email` is part of the Manual key, the new key generated from the source record (`Bob` + `bobNew@company.com`) no longer matched the existing target record's key (`Bob` + `bob@company.com`). With no match found, Manual inserted a new record in the target org instead of updating the existing one, resulting in a duplicate.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.flosum.com/data-migrator/templates/migration/how-record-mapping-works.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
