Google Sheets Two-Way Sync with Dataverse
Bidirectionally syncs a Google Sheet with a Dataverse table: sheet edits upsert to Dataverse and Dataverse changes write back to the matching row, keyed on an ID column with a source flag to prevent loops. Lets a business team work in Google Sheets while apps and reporting run on Dataverse.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
Google Sheets Two-Way Sync with Dataverse keeps a Google Sheets worksheet and a Dataverse mirror table in sync both directions, loop-safely. Sheet edits upsert into Dataverse; Dataverse (app-side) changes write back to the matching sheet row. Each row is keyed on a shared SyncId column, and a Source flag breaks the echo loop so a write in one system doesn't bounce back forever.
Why it matters: A business team prefers working in Google Sheets, while apps, automation, and reporting run on Dataverse. A loop-safe two-way sync gives both sides an authoritative, current copy of the data without double entry.
This is a two-flow solution: a scheduled poll for the Sheet to Dataverse direction (Google Sheets has no change trigger) and a Dataverse change-trigger flow for the Dataverse to Sheet direction. Both ship Off.
Use Case
A team maintains operational data (action items, inventory, a project tracker, etc.) in a Google Sheet that must stay consistent with a Dataverse-backed model-driven app. Edits made in either tool should appear in the other within a polling cycle, without manual re-keying and without infinite update loops.
Flow Architecture
Recurrence Poll Google Sheet (Flow A)
Recurrence (every 15 min)Re-read the worksheet on a schedule for the Sheet to Dataverse direction.
Initialize Correlation Id
Init var @guid()Trace id for this run.
Initialize env-var bindings
Init varsLoad env vars (spreadsheet, worksheet, table, id/title/status columns, Teams group/channel) plus the synced counter.
Get Sheet Rows
Google Sheets GetItemsRead all rows of the worksheet.
Apply to each Sheet Row
ForeachUpsert each row.
List Matching Record
Dataverse ListRecordsFind existing row where flowlibs_syncid eq this row's key.
Condition Record Exists
If length(...) > 0Update vs. create.
Update / Create Dataverse Record
Dataverse UpdateRecord / CreateRecordRefresh or create the mirror row (Source = sheet).
Post Sync Summary To Teams
Teams PostMessageToConversationPost run summary.
When a Dataverse Row Changes (Flow B)
Dataverse SubscribeWebhookTrigger (scope: Organization)Fire on row modifications to the mirror table for the Dataverse to Sheet direction.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_GSheetId | String | <configure> | Google Sheets file id. |
| flowlibs_GSheetWorksheet | String | ActionItems | Worksheet/tab name. |
| flowlibs_SyncTable | String | flowlibs_gsheetsyncitems | Dataverse entity-set name to mirror. |
| flowlibs_IdColumn | String | SyncId | Sheet header that keys each row across systems. |
| flowlibs_TitleColumn | String | Title | Sheet header for the title field. |
| flowlibs_StatusColumn | String | Status | Sheet header for the status field (two-way). |
| flowlibs_TeamsGroupId | String | <your-team-id> | Teams team id for notifications. |
| flowlibs_TeamsChannelId | String | <your-channel-id> | Teams channel id for notifications. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Google Sheets | shared_googlesheet | GetItems GetItem PatchItem |
| Microsoft Dataverse | shared_commondataserviceforapps | SubscribeWebhookTrigger ListRecords CreateRecord UpdateRecord |
| Microsoft Teams | shared_teams | PostMessageToConversation |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Point at your data
- Set flowlibs_GSheetId to your spreadsheet id and flowlibs_GSheetWorksheet to the tab. The worksheet needs at least the columns named in flowlibs_IdColumn (SyncId), flowlibs_TitleColumn (Title), and flowlibs_StatusColumn (Status).
- Conflict policy
- As shipped this is last-writer-wins with the sheet poll as the authority. For true bidirectional authority, add Dataverse logic that stamps flowlibs_source = dataverse on app edits so Flow B writes those edits back.
- New rows
- Generate a unique SyncId for fresh sheet rows. A Dataverse row created app-side with no flowlibs_gsheetrowid is not written back; extend Flow B with a Google Sheets PostItem (append) branch.
- Deletes
- The demo does not propagate deletions. Prefer a soft-delete pattern (a status value) over removing rows.
- Field map
- Add columns by extending the item/... mappings in Flow A and the setProperty(...) chain in Flow B; keep both sides in step.
- Polling frequency
- Adjust the Recurrence interval (15 min default) to balance freshness vs. API calls.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Loop guard (Flow B condition)
Only writes back changes that did not originate from the sheet sync.
EXPR.02Upsert lookup (Flow A $filter)
Finds the matching Dataverse record by SyncId.
EXPR.03Dynamic sheet-column read
Reads the row's key cell by configured header name.
EXPR.04Partial write-back preserving other columns
Writes Title and Status back without blanking other columns.
EXPR.05Sheet row id for write-back targeting
Stores the sheet row id so Flow B can target the correct row.
Customize & download
Generate a ready-to-import copy of this solution with your environment-variable values baked in — available on Base, Pro, or Team.
Upgrade to customize
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.