Tips > Building Workflows

Transform Data Shapes Between Incompatible Nodes

Different SaaS platforms structure data in incompatible ways.

Different SaaS platforms structure data in incompatible ways. A Code node between them acts as an adapter layer, reshaping the output of one node to match the expected input of another.

Real-world example: Syncing records from Airtable (which returns linked records as arrays of IDs) to Notion (which expects relation properties as arrays of page IDs with specific formatting).

// Mode: Run Once for All Items

// Mapping of Airtable record IDs to Notion page IDs (pre-built or fetched)
const idMap = $input.first().json.idMapping; // { airtableId: notionPageId }

return $input.all().slice(1).map(item => {
  const record = item.json;

  // Airtable returns: { "Assignees": ["recABC", "recDEF"], "Status": "In Progress" }
  // Notion expects: specific property format per type

  return {
    json: {
      parent: { database_id: 'your-notion-database-id' },
      properties: {
        // Title property
        'Task Name': {
          title: [{ text: { content: record['Task Name'] || 'Untitled' } }]
        },
        // Select property
        'Status': {
          select: { name: mapStatus(record['Status']) }
        },
        // Relation property -- map Airtable IDs to Notion page IDs
        'Assignees': {
          relation: (record['Assignees'] || [])
            .map(airtableId => idMap[airtableId])
            .filter(Boolean)
            .map(notionId => ({ id: notionId }))
        },
        // Date property
        'Due Date': {
          date: record['Due Date']
            ? { start: record['Due Date'], end: null }
            : null
        },
        // Number property
        'Story Points': {
          number: parseInt(record['Story Points'], 10) || null
        },
      }
    }
  };
});

function mapStatus(airtableStatus) {
  const statusMap = {
    'To Do': 'Not started',
    'In Progress': 'In progress',
    'Done': 'Complete',
    'Blocked': 'Blocked',
  };
  return statusMap[airtableStatus] || 'Not started';
}
```text
This pattern is reusable for any SaaS-to-SaaS sync. Keep the mapping logic centralized in one Code node to make future field changes easy.

**Related:** [Use Edit Fields in "Map Each" Mode for Simple Renames](../data-transformation/01-use-edit-fields-in-map-each-mode-for-simple-renames.md) | [Configure Payload Size and Binary Data Mode for Large Files](../performance-and-large-files/01-configure-payload-size-and-binary-data-mode-for-large-files.md)

Showcase builds

19 complete workflows from my own projects, each with its n8n workflow JSON to import. Showcase entries link the file at the end of the article.

See the showcase builds

Keep reading

191 entries grouped by topic, from first workflow to queue mode. Free, no signup.

Browse the encyclopedia

Need it built?

I design, build and run n8n systems for clients. Every engagement starts with a $1,500 diagnostic audit, credited toward the build.

Book a 20-minute call