Dynamics 365 Dual-write: F&O to Dataverse Bidirectional Sync
What is Dynamics 365 Dual-write - F&O to Dataverse sync, 1000-record limit, 2-minute timeout?
TL;DR
- Bottom line: Dual-write provides near-real-time, bidirectional synchronization between Dynamics 365 Finance & Operations (F&O) apps and Microsoft Dataverse (CE apps) using an out-of-box, no-code/low-code framework with pre-built table maps. [src1]
- Key limit: 1,000 records per transaction from F&O to Dataverse, with a hard 2-minute timeout on all live sync transactions in both directions. [src2]
- Watch out for: Initial sync has a separate 500,000-row-per-run limit per legal entity, and single-threaded tables (Customers V3, Vendors V2) cannot exceed 70,000 rows from Dataverse without timing out. [src3]
- Best for: Keeping master data (customers, products, vendors) synchronized in near-real-time between F&O and CE apps (Sales, Customer Service, Field Service). [src1]
- Authentication: Managed by Power Platform integration -- no separate OAuth setup required; environments are linked via Lifecycle Services (LCS) or Power Platform admin center. [src1]
System Profile
Dual-write is a Microsoft-provided infrastructure that enables near-real-time, bidirectional data synchronization between Dynamics 365 Finance & Operations (F&O) apps and customer engagement (CE) apps built on Microsoft Dataverse. It ships as two Marketplace solutions installed on Dataverse that extend the table schema, plugins, and workflows to handle ERP-scale data volumes. Covers all F&O SKUs (Finance, Supply Chain Management, Commerce, Project Operations). Does NOT cover Business Central integrations.
| Property | Value |
|---|---|
| Vendor | Microsoft |
| System | Dynamics 365 Finance & Operations (10.0.x, continuous updates) |
| API Surface | Dual-write (bidirectional OData-based sync framework) |
| Current Version | Continuously updated via Marketplace solutions |
| Editions Covered | Finance, Supply Chain Management, Commerce, Project Operations |
| Deployment | Cloud (required) |
| API Docs | Dual-write documentation |
| Status | GA (Generally Available) |
API Surfaces & Capabilities
Dual-write is a synchronization framework, not a traditional API. It uses table-to-table maps defining how data flows between F&O data entities and Dataverse tables, handling OData and plugin orchestration automatically.
| Capability | Protocol | Best For | Max Records/Request | Timeout | Real-time? | Bidirectional? |
|---|---|---|---|---|---|---|
| Live Sync (F&O to Dataverse) | OData/Plugins | Individual record CRUD, master data | 1,000 records/transaction | 2 min | Yes | Yes |
| Live Sync (Dataverse to F&O) | OData/Plugins | Individual record CRUD, master data | 116.85 MB payload/transaction | 2 min | Yes | Yes |
| Initial Sync (F&O to Dataverse) | Batch export | Bulk data load, go-live migration | 500,000 rows/run/legal entity | 5 min (export) | No | Configurable |
| Initial Sync (Dataverse to F&O) | Batch import | Bulk data load, go-live migration | 500,000 rows/run/legal entity | 24 hours | No | Configurable |
| Catchup Sync | Queue-based | Recovery after pause/maintenance | Queue-based (no explicit limit) | 1 day retention | No | Yes |
Rate Limits & Quotas
Per-Transaction Limits (Live Sync)
| Limit Type | Value | Direction | Notes |
|---|---|---|---|
| Max records per transaction | 1,000 | F&O to Dataverse | Split transactions with >1,000 records into batches of 1,000 |
| Max payload per transaction | 116.85 MB | Dataverse to F&O | Error code -2147220970 if exceeded |
| Transaction timeout | 2 minutes | Both directions | All transactions exceeding 2 min are rolled back on both sides |
| Legal entities (live sync) | 250 | Both | Limit during live synchronization |
| Legal entities (environment linking) | 40 | Setup phase | Error if >40 legal entities during initial linking |
| Concurrent requests | Governed by Dataverse service protection limits | F&O to Dataverse | Per-tenant daily API call limits apply |
Initial Sync Limits
| Limit Type | Value | Direction | Notes |
|---|---|---|---|
| Max rows per run | 500,000 | Both | Per legal entity; each legal entity runs separately |
| Single-threaded table max rows | 70,000 | Dataverse to F&O | Timeout if exceeded; migrate data separately instead |
| F&O data export timeout | 5 minutes | F&O to Dataverse | Optimize queries, add missing indexes, check virtual columns |
| F&O import result timeout | 24 hours | Dataverse to F&O | For very large datasets, migrate independently |
| Max lookups per table map | 10 | Dataverse initial sync | Split lookups into batches if >10 |
| Visible errors in error log | 5 | Both | Only top 5 errors shown per initial sync run |
Authentication
Dual-write does not require separate OAuth or API key authentication. The integration is established by linking F&O and Dataverse environments through the Power Platform integration process.
| Setup Method | Use When | Configuration | Notes |
|---|---|---|---|
| Power Platform Integration (LCS) | New F&O deployments | Link via LCS environment setup | Recommended for new implementations |
| Power Platform Admin Center | Existing environments | Connect existing F&O to existing Dataverse | Requires Global Admin or Dynamics 365 Admin role |
| Dual-write Connection Setup | After environment linking | Configure in F&O Dual-write admin workspace | Only the linking user can create initial maps |
Authentication Gotchas
- Only the user who set up the Dual-write connection can create table maps -- other admins cannot create maps without re-establishing the connection. [src5]
- All dual-write users in CE must be assigned the Dual-Write Runtime User security role or they cannot create rows in synced tables. [src3]
- All dual-write users need the Dual-Write App User role for read access to Company and Currency Exchange tables, which are global. [src3]
Constraints
- 1,000 record transaction limit: F&O-to-Dataverse live sync aborts any single transaction with >1,000 records. Custom X++ code must split batches using
ttsbegin/ttscommitblocks of 1,000 or fewer. [src2] - 2-minute timeout: Both sides must commit within 2 minutes. Includes time for Dataverse plugins (standard + custom). Can be increased to 5 minutes only via Microsoft Support request. [src2]
- Cloud-only: Dual-write requires cloud-hosted F&O and Dataverse. On-premise F&O deployments cannot use Dual-write. [src1]
- No partial retry on initial sync: If individual rows fail during initial sync, you cannot resync only those rows -- the first run is a full push. Subsequent runs with change tracking are incremental. [src3]
- Double quotes in data: Double quotes in source data fields cause initial sync to fail with MalformedLineException. Data must be cleaned before sync. [src3]
- Cross-company data sharing incompatibility: Dual-write does not support F&O entities with cross-company data sharing enabled (DIPV1002 error). [src5]
Integration Pattern Decision Tree
START -- User needs to sync data between F&O and Dataverse/CE apps
|-- Is the data master data (customers, vendors, products)?
| |-- YES --> Dual-write with pre-built table maps
| |-- NO --> Is it transactional data (orders, invoices)?
| |-- YES --> Dual-write (prospect-to-cash, procure-to-pay)
| |-- NO --> Consider Data Management Framework or custom integration
|-- What's the data volume per transaction?
| |-- < 1,000 records --> Standard Dual-write live sync
| |-- 1,000-500,000 records --> Split into transactions of 1,000 records each
| |-- > 500,000 records --> Migrate independently, skip initial sync
|-- Do you need bidirectional sync?
| |-- YES --> Dual-write (design conflict resolution via "Master" setting)
| |-- NO, read-only from F&O --> Consider Virtual Entities (no data duplication)
|-- Is the F&O environment cloud-hosted?
| |-- YES --> Dual-write supported
| |-- NO (on-premise) --> Dual-write NOT supported; use OData or custom integration
|-- Encountering timeouts?
| |-- Transaction timeout (2 min) --> Optimize Dataverse plugins, reduce mapped fields
| |-- Initial sync timeout --> Check data volume against limits
Quick Reference: Pre-built Table Maps
| Category | Example Maps | F&O Entity | Dataverse Table | Threading | Notes |
|---|---|---|---|---|---|
| Customer Master | Customers V3 | CustCustomerV3Entity | account | Single | Max 70K rows from Dataverse |
| Vendor Master | Vendors V2 | VendVendorV2Entity | msdyn_vendor | Single | Max 70K rows from Dataverse |
| Product Master | Released products V2 | EcoResReleasedProductV2Entity | msdyn_sharedproductdetail | Multi | Up to 500K rows |
| Sales | Sales order headers/lines | SalesOrderHeaderV2Entity | salesorder | Multi | Prospect-to-cash |
| Inventory | On-hand inventory | InventOnHandEntity | msdyn_inventoryonhand | Multi | Near-real-time availability |
| Project | Project contracts/tasks | ProjProjectEntity | msdyn_project | Multi | Project Operations |
| Finance | Ledger/Currencies | LedgerEntity | msdyn_ledger | Multi | Prerequisite for all maps |
| Organization | Legal entities | CompanyInfoEntity | cdm_company | Multi | Must be synced first |
Step-by-Step Integration Guide
1. Link F&O and Dataverse environments
Establish the Power Platform integration by connecting your F&O environment to a Dataverse instance via LCS or Power Platform Admin Center. [src1]
Via LCS:
1. Open LCS > Environment details for your F&O environment
2. Click "Power Platform Integration" > "Setup"
3. Select existing Dataverse environment or create new one
4. Confirm linking
Verify: In F&O, navigate to System Administration > Setup > Dual-write -- the admin workspace should appear.
2. Install Dual-write Marketplace solutions
Install the two required solutions on your Dataverse environment from the Dynamics 365 admin center. [src1]
Via Power Platform Admin Center:
1. Navigate to admin.powerplatform.microsoft.com
2. Select your Dataverse environment
3. Go to Resources > Dynamics 365 apps
4. Install "Dual-write core solution" and "Dual-write application solution"
5. Wait 10-30 minutes for installation
Verify: Open Dual-write admin workspace in F&O -- table maps should populate.
3. Configure and run initial synchronization
Run initial sync following the dependency order: Company > Currency > Customers > Vendors > Products > Transactional data. [src3]
Recommended order:
1. Company and currencies (prerequisites)
2. Chart of accounts and financial dimensions
3. Customers V3 (single-threaded: <70K rows from Dataverse)
4. Vendors V2 (single-threaded: <70K rows from Dataverse)
5. Products (multi-threaded: up to 500K rows)
6. Sales orders and lines
7. Remaining maps
For tables >500K rows: migrate independently + skip initial sync
Verify: Check Initial sync details tab -- status should show Completed.
4. Configure alert notifications for production
Set up error thresholds to automatically pause Dual-write during outages. [src4]
In Dual-write admin workspace:
1. Select table map to monitor
2. Click "Create alert settings"
3. Configure: 10 Application errors in 15 minutes > Pause + email
4. Restart table map for alerts to take effect
Verify: Trigger a test error and confirm notification delivery + automatic pause.
Code Examples
X++: Split large transactions into Dual-write-safe batches
// Input: Collection of records to create in F&O (syncs to Dataverse)
// Output: All records created in batches of 1,000 within 2-min timeout
int batchCounter = 0;
boolean commitPending = false;
while select myRecordBuffer
where myRecordBuffer.Status == MyStatus::Pending
{
if (batchCounter == 0)
{
ttsbegin;
commitPending = true;
}
myRecordBuffer.insert(); // Triggers Dual-write sync
batchCounter++;
if (batchCounter >= 1000)
{
ttscommit;
commitPending = false;
batchCounter = 0;
}
}
if (commitPending)
{
ttscommit; // Commit remaining records
}
PowerShell: Monitor Dual-write map status
# Input: Dataverse environment URL + access token
# Output: List of Dual-write table maps and status
$envUrl = "https://yourorg.crm.dynamics.com"
$token = "Bearer <your-access-token>"
$response = Invoke-RestMethod `
-Uri "$envUrl/api/data/v9.2/dualwriteentitymaps" `
-Headers @{ "Authorization" = $token; "Accept" = "application/json" } `
-Method Get
$response.value | ForEach-Object {
[PSCustomObject]@{
Name = $_.msdyn_name
Status = $_.msdyn_status
LastSync = $_.msdyn_lastsynctime
ErrorCount = $_.msdyn_errorcount
}
} | Format-Table -AutoSize
Data Mapping
Table Map Architecture
| F&O Entity | Dataverse Table | Direction | Key Fields | Threading |
|---|---|---|---|---|
| CustCustomerV3Entity | account (Customers V3) | Bidirectional | CustomerAccount | Single-threaded |
| VendVendorV2Entity | msdyn_vendor (Vendors V2) | Bidirectional | VendorAccountNumber | Single-threaded |
| EcoResReleasedProductV2Entity | msdyn_sharedproductdetail | Bidirectional | ProductNumber | Multi-threaded |
| SalesOrderHeaderV2Entity | salesorder | Bidirectional | SalesOrderNumber | Multi-threaded |
| CompanyInfoEntity | cdm_company | Bidirectional | DataAreaId | Prerequisite |
| CurrencyEntity | transactioncurrency | F&O to Dataverse | CurrencyCode | Prerequisite |
Data Type Gotchas
- Currency decimal precision: Dual-write extends Dataverse currency fields from 4 to up to 10 decimal places. Requires opt-in feature toggle; without it, rounding differences cause sync failures. [src1]
- Date effectivity: F&O supports date-effective records (past, present, future on same table). Dual-write adds this concept to Dataverse tables. [src1]
- Company/Legal Entity scoping: Every F&O record is scoped to a legal entity (DataAreaId). Company must be synced before any company-scoped data. [src3]
- Double quotes in string fields: Cause MalformedLineException during initial sync. Must be cleaned from source data. [src3]
Error Handling & Failure Points
Common Error Codes
| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| DIPV1000 | Connection validation failed | Power Apps ApiHub connections expired | Re-create connection sets |
| DIPV1002 | Cross-company data sharing conflict | Cross-company sharing enabled on F&O entity | Disable cross-company sharing or use different entity |
| DIPV1003 | Integration keys missing | No alternate key on Dataverse table | Define alternate key in Power Apps maker portal |
| DIPV1010 | Mandatory field unmapped | Required field not mapped in table map | Map all mandatory fields or add default transforms |
| DIPV1019 | Missing versionnumber field | Unsupported table type (virtual/elastic) | Use standard table with versionnumber field |
| -2147220970 | Message size exceeded | Payload >116.85 MB from Dataverse | Split transaction into smaller batches |
| MalformedLineException | Double quote parsing failure | Double quotes in source data | Remove double quotes before syncing |
Failure Points in Production
- Transaction timeout during high-volume operations: Synchronous Dataverse plugins consume the 2-minute window. Fix:
Move heavy plugins to async; reduce mapped field count. [src2] - Initial sync stuck at 0%: F&O data export taking >5 min due to virtual columns or missing indexes. Fix:
Add missing indexes; update to PU37+. [src3] - Catch-up queue purge: Error records auto-deleted after 1 day. Fix:
Monitor daily; retry or export before 24-hour purge. [src4] - Legal entity limit error: >40 legal entities during setup triggers "Exceeds maximum partitions." Fix:
Link only needed entities; 250 limit applies post-setup. [src3] - Cascading map failures: Stopping parent map while dependent maps run causes failures. Fix:
Stop in reverse dependency order; restart: Company > Currency > Customers. [src3, src7] - Data conflicts on resume: Records fail validation in destination after pause/resume. Fix:
Review catch-up errors tab; retry after fixing validation issues. [src4]
Anti-Patterns
Wrong: Running Dual-write maps during bulk data migration
// BAD -- Each migrated record triggers individual sync, destroying performance
1. Enable Dual-write map for Customers V3
2. Start DMF import of 200,000 customers
3. Each insert triggers sync -- 200K individual operations
4. Result: hours instead of minutes; possible timeouts
Correct: Complete migration first, then enable Dual-write
// GOOD -- Migrate independently, then enable live sync
1. Import 200,000 customers into F&O via DMF
2. Import matching 200,000 accounts into Dataverse
3. Enable Dual-write maps with "Skip initial sync"
4. Result: migration in minutes; Dual-write handles only new changes
Wrong: Creating >1,000 records in a single X++ transaction
// BAD -- Exceeds Dual-write 1,000-record limit
ttsbegin;
while select forUpdate myRecord where myRecord.Status == Status::New
{
myRecord.Status = Status::Active;
myRecord.update(); // All 5,000 updates in ONE transaction
}
ttscommit; // FAILS: Dual-write rejects >1,000 records
Correct: Batch records into groups of 1,000
// GOOD -- Split into safe batches
int counter = 0;
ttsbegin;
while select forUpdate myRecord where myRecord.Status == Status::New
{
myRecord.Status = Status::Active;
myRecord.update();
counter++;
if (counter >= 1000) { ttscommit; ttsbegin; counter = 0; }
}
ttscommit;
Wrong: Running Contact initial sync while Customer map is active
// BAD -- Shared address tables cause lock contention
1. Customer V3 map: Running (live sync active)
2. Start initial sync for Contacts
3. Result: performance degradation, address table locks, errors
Correct: Pause Customer map during Contact initial sync
// GOOD -- Stop conflicting maps first
1. Pause Customer V3 map
2. Run Contact initial sync to completion
3. Resume Customer V3 map (catchup handles queued changes)
Common Pitfalls
- Not syncing prerequisite maps first: Company and Currency must be synced before company-scoped data. Fix:
Follow dependency order: Company > Currency > Customers > Vendors > Products. [src3] - Sandbox != production limits: Sandbox has lower Dataverse API limits and less compute. Fix:
Load-test with production-equivalent data volumes. [src7] - Ignoring single-threaded constraints: Treating Customers V3 as multi-threaded leads to timeouts >70K rows. Fix:
Migrate single-threaded tables independently; skip initial sync. [src3] - Missing Dual-Write security roles: Users without Runtime User or App User roles fail on synced tables. Fix:
Assign both roles to all CE users in Dual-write processes. [src3] - Heavy synchronous plugins on synced tables: Custom plugins consume the 2-minute timeout budget. Fix:
Convert to async; optimize to <500ms. [src2, src7] - Unmonitored error queues: Catch-up errors purged after 24 hours = permanent data loss. Fix:
Configure alert notifications in admin workspace; set email alerts. [src4]
Diagnostic Commands
# Check Dual-write map status in F&O
# Navigate: System Administration > Setup > Dual-write > Table maps
# Check initial sync progress
# Dual-write admin workspace: select map > "Initial sync details" tab
# View catch-up errors after resume
# Dual-write admin workspace: select map > "Catch-up errors" tab
# Check Dataverse API limits usage
# Power Platform Admin Center > Environments > Analytics > API calls
# Test environment connectivity
# Dual-write admin workspace: "Test connection" button
# View activity log for a table map
# Dual-write admin workspace: select map > "Activity log" tab
# Download detailed error logs
# Activity log: click event > "Download logs"
Version History & Compatibility
| Release | Date | Status | Key Changes | Notes |
|---|---|---|---|---|
| Continuous updates (2026) | Ongoing | Current | MCP server for Dataverse (GA) | Per-update release cadence |
| 2024 Wave 2 | 2024-10 | Supported | Legal entity limit: 40 to 250 (live sync) | Major scalability improvement |
| 2021 Wave 1 | 2021-04 | Supported | Catchup write management; alert notifications | First error queue UI |
| PU37+ | 2020-11 | Minimum required | 5-min export timeout handling | Required for reliable initial sync |
| Original GA | 2019 | Legacy | Initial Dual-write release | No longer recommended |
When to Use / When Not to Use
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Bidirectional near-real-time master data sync between F&O and CE apps | Read-only access to F&O data (no duplication needed) | Virtual Entities |
| Pre-built scenarios: prospect-to-cash, procure-to-pay, project-to-cash | Bulk migration >500K rows per legal entity | Data Management Framework |
| No-code/low-code integration between Microsoft D365 apps | Integration with non-Microsoft systems (SAP, Salesforce) | OData API or Azure Integration Services |
| Cloud-hosted F&O environment | On-premise F&O deployment | OData endpoints or custom API |
| Transaction volumes <1,000 records per operation | High-frequency, >1,000 records/second | Batch processing or event-driven architecture |
Cross-System Comparison
| Capability | Dual-write | Virtual Entities | DMF | OData API |
|---|---|---|---|---|
| Data Direction | Bidirectional | Read-only from F&O | Import/Export | Full CRUD |
| Data Storage | Copied to both systems | Data stays in F&O only | Staging tables | Per-request |
| Latency | Near-real-time (<1s) | Real-time (query-time) | Batch (min to hrs) | Real-time |
| Max Records/Op | 1,000/transaction | No limit (query-based) | Millions (file-based) | Standard OData limits |
| Storage Cost | Double (data in both) | None | Staging only | None |
| Setup Complexity | Low (pre-built maps) | Low (configuration) | Medium (packages) | High (custom dev) |
| Offline Support | Yes (catchup on resume) | No | Yes (file-based) | No |
| Custom Table Support | Yes (extensible) | Yes (configurable) | Yes | Yes |
| Best Use Case | Master data sync | Reporting, lookups | Bulk migration, ETL | Custom integrations |
Important Caveats
- Dual-write is cloud-only: on-premise F&O deployments cannot use it. Hybrid scenarios require Azure-based middleware. [src1]
- The 2-minute timeout includes ALL Dataverse processing: standard plugins, custom plugins, workflows, and business rules all consume from the same budget. Heavy customization is the #1 cause of timeout failures. [src2]
- Initial sync and live sync have different limits: 500K rows per run vs. 1,000 records per transaction. Error handling also differs (full push vs. per-record retry). [src2, src3]
- Microsoft can increase the 2-minute timeout to 5 minutes via support request, but this should be a last resort after optimizing plugins and field mappings. [src2]
- Dual-write pricing is included with F&O licenses -- no additional API call costs. However, Dataverse storage costs increase due to data duplication. [src6]
- Information in this card is subject to change with each Microsoft release wave. Always verify current limits against official Microsoft Learn documentation. [src1]