{"id":4832,"date":"2018-03-19T07:00:32","date_gmt":"2018-03-19T14:00:32","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=4832"},"modified":"2025-06-13T23:43:12","modified_gmt":"2025-06-14T06:43:12","slug":"document-conflicts-couchbase-mobile","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/","title":{"rendered":"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0"},"content":{"rendered":"<p>Document conflicts can occur in distributed environments that support data synchronization, wherein a document can be updated concurrently by one or more writers. This is especially common in mobile environments where unreliable network connections may result in concurrent changes from multiple devices not being synchronized in a timely fashion.<\/p>\n<p>It can also occur on the client-side, for instance, if a document is being updated locally while changes to the document are being pulled down to the client from a remote server. Hence, there is a need to resolve these document conflicts. \u00a0<a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/2.0\/whatsnew.html\">Couchbase Mobile 2.0<\/a>, introduces <em>\u201cAutomatic Conflict Resolution\u201d<\/em> or a\u00a0<em>\u201cConflict-free\u201d<\/em> mode wherein conflicts are automatically handled and there are effectively no conflicting document revisions in the Couchbase database.<\/p>\n<p>As an app developer, you probably wouldn\u2019t ever have to do anything specific on the app side in order to deal with conflicts because the system\u2019s default conflict resolver will automatically handle things for you. However, if you need to, you have the option of being notified of conflicts and can take appropriate action. This post will discuss the fundamentals of how document conflicts are automatically handled in Couchbase Mobile 2.0 using the \u201c<em>automatic conflict resolution<\/em>\u201d or \u201c<em>conflict-free <\/em>\u201d mode.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<h2 id=\"assumptions\">Assumptions<\/h2>\n<p>This post assumes that you are familiar with the architecture of Couchbase Mobile stack that includes the <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/current\/guides\/couchbase-lite\/index.html\">Couchbase Lite<\/a> embedded database for your mobile clients, the <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/current\/guides\/sync-gateway\/index.html\">Sync Gateway<\/a> and <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/current\/introduction\/intro.html\">Couchbase Server<\/a>. If you are new to the platform, I would recommend catching with these <a href=\"https:\/\/www.couchbase.com\/developers\/mobile\/\">resources<\/a>.<\/p>\n<h2 id=\"background\">Background<\/h2>\n<p>If you haven\u2019t done so, it would be worthwhile reading this earlier <a href=\"https:\/\/www.couchbase.com\/blog\/conflict-resolution-couchbase-mobile\/\">demystifying conflict resolution post<\/a> that discusses the fundamentals of how conflict resolution is handled on \u201cnon-conflict-free\u201d mode in Couchbase Mobile including an overview Multi-Version Concurrency Control (MVCC) system.<\/p>\n<h3 id=\"documentrevisiontree\">Document Revision Tree<\/h3>\n<p>To understand the conflict resolution process, you would have to a basic understanding of how documents are stored. In Couchbase Mobile, every document is assigned a unique system-generated revision ID or <em>revID<\/em>. This ID is in addition to the document ID which remains the same across document revisions. Every change to a document, be it a modification or a delete is treated as a new revision to the document and is hence, assigned a new revision ID.<\/p>\n<p>In addition, every document revision has a \u201c<em>generationID<\/em>\u201d associated with it. The first time a document is created, a revision gets created with a \u201c<em>generationID<\/em>\u201d of 1. Every subsequent revision update will increment this number.<\/p>\n<p>Every time a change (edit or delete) is to be made to an existing document, the writer must include the revision ID of the current revision of the document that is being updated. A new revision is created for the change and added as a child node to the current revision that was being updated, resulting in a Revision Tree for the document.<\/p>\n<p>NOTE: The <em>\u201crevID\u201d<\/em> must be treated as an opaque object by the app and the app must not try to generate the <em>\u201crevID\u201d<\/em>.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/05\/revision-tree-latest.png\" alt=\"\" \/><\/figure>\n<h2 id=\"howdocumentconflictsoccur\">How Document Conflicts Occur<\/h2>\n<p>At a high level, a conflict occurs when changes are made to the same parent revision of a document by multiple writers.<\/p>\n<h3 id=\"conflictatcouchbaselite\">Conflicts At Couchbase Lite<\/h3>\n<p>The illustration below describes a scenario where an app is updating a document revision in memory while the same revision is being updated as a result of a pull replication.<br \/>\n<img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/03\/cbl_conflict-1.png\" alt=\"\" \/><\/p>\n<h3 id=\"conflictatsyncgateway\">Conflicts At Sync Gateway<\/h3>\n<p>The illustration below describes a scenario where two clients push up changes to the same revision of the document.<br \/>\n<img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/05\/conflict-basics-1.png\" alt=\"\" \/><\/p>\n<h2 id=\"conflictfreemodeincouchbasemobile2.0\">Conflict Resolution in Couchbase Mobile 2.0<\/h2>\n<p>In <em>\u201cConflict-Free\u201d<\/em> mode, the Sync Gateway essentially rejects all conflicting updates. The conflicts are automatically resolved at the time the document is created, updated or deleted.<br \/>\nSo the implication of this is that there are no conflicting documents stored in the database and is effectively, \u201c<em>Conflict Free<\/em>\u201d. We will take a look at how this works.<\/p>\n<h3 id=\"automaticconflictresolutionincouchbaselite2.0\">Automatic Conflict Resolution in Couchbase Lite 2.0<\/h3>\n<p>Every document in Couchbase Lite 2.0 is associated with a <em>\u201cconflict resolver\u201d<\/em> that is executed if a conflict occurs when an attempt is made to <code>save<\/code> or <code>delete<\/code> a document. The conflict resolver function chooses a \u201c<em>winner<\/em>\u201d among the conflicting revisions and this winner is added as a child to the document revision tree.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/01\/conflict-resolver-basics.png\" alt=\"\" \/><\/figure>\n<p>There are two concurrency control policies supported by Couchbase Lite.<\/p>\n<h4 id=\"concurrencycontrolpolicy\">Concurrency Control Policy<\/h4>\n<h5 id=\"lastwritealwayswinsdefault:\"><strong>Last Write Always Wins (Default):<\/strong><\/h5>\n<p>This is also the default conflict resolver policy. In this case, the last update to the database always wins.<\/p>\n<p>When you call <code>saveDocument<\/code> with no Concurrency Control argument, this is the policy that is in effect by default.<\/p>\n<p>This is an example of the call in swift.<\/p>\n<pre><code class=\"swift\"> let savedDocument = try saveDocument(docToSave)<\/code><\/pre>\n<p>The examples below should clarify the implications of this policy<\/p>\n<ul>\n<li>\u00a0For example, our save \/ update request succeeds even though the document in the database was updated since the last time we read the document. The document in the database could have been updated by a different thread in the app as a result of some external trigger such as a pull replication or a data fetch from a remote server. The implication is that any changes that were made to the document between the time we read the document and updated it would be overwritten.<\/li>\n<\/ul>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/03\/conflict-free-last-write-wins.png\" alt=\"\" \/><\/figure>\n<ul>\n<li>As below, our save \/ update request succeeds even though the document in the database was deleted since the last time we read the document. The document in the database could have been updated by a different thread in the app as a result of some external trigger such as a pull replication or a data fetch from a remote server. The implication is that a deleted document could be resurrected as a result of the save.<\/li>\n<\/ul>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/03\/conflict-free-last-write-wins-on-delete-1.png\" alt=\"\" \/><\/figure>\n<h5 id=\"failonconflict\"><strong>Fail On Conflict<\/strong><\/h5>\n<p>While we anticipate that the default concurrency control policy of \u201clast write wins\u201d should work for most cases, you can override the default behavior by specifying that you wish to be notified in case of a conflict while saving the document. This can be done by including the optional <em>ConcurrentControl<\/em> argument as part of the save request.<\/p>\n<p>A return value <code>false<\/code> with a <em>ConcurrencyControl <\/em>policy <code>failOnConflict<\/code> indicates that the document saved failed as a result of a conflict. We will now examine how you can handle conflict errors.<\/p>\n<h4 id=\"handlingfailonconflicts\">Handling Fail on Conflicts<\/h4>\n<p>How you handle conflicts depends on the application semantics. Here are examples of how you can handle it in swift (which can be easily mapped to other languages)<\/p>\n<ul>\n<li><strong>Option 1:<\/strong>\u00a0<strong>Merge the conflicting versions of the document and save<\/strong><\/li>\n<\/ul>\n<pre><code class=\"swift\">do {\r\n    var success = false\r\n    repeat {\r\n        if try db.saveDocument(docToSave, concurrencyControl: .failOnConflict) {\r\n            \/\/ save was a success. docToSave is the new saved revision. Proceed as usual\r\n            success = true\r\n        }\r\n        else {\r\n            \/\/ Failure on save with failOnConflict mode\r\n            \/\/ Handle conflict appropriately\r\n            \/\/ First, fetch the current saved version of doc\r\n            if let currDoc = db.document(withID: docToSave.id) {\r\n                \/\/ Option 1 : Merge the contents of doc1b and currDoc\r\n                docToSave = mergeDocument(newDoc: docToSave, currentDoc: currDoc)\r\n            }\r\n            else {\r\n                \/\/ Doc was deleted. Handle appropriately\r\n            }\r\n        }\r\n        \r\n    } while (!success)\r\n}\r\ncatch {\r\n    print(\"Some other error in saving \\(error)\")\r\n}<\/code><\/pre>\n<p>This is an example of how you would merge the conflicting revisions. Again, how you would do it is entirely up to your application. This is intended to be a reference implementation on how you <em>could<\/em> handle it.<\/p>\n<pre><code class=\"swift\">\r\n\/\/\/ Merges two conflicting versions of CBL document using following criteria\r\n\/\/\/ - Newly added properties are added \r\n\/\/\/ - If we are updating an existing property, that is ignored a property that already exists\r\n\/\/\/\r\n\/\/\/ - Parameter \r\n\/\/\/   - newDoc: The new version of document to be saved\r\n\/\/\/   - currentDoc : The current saved version of the document\r\nfunc mergeDocument(newDoc: Document, currentDoc: Document) -&gt; MutableDocument {\r\n    \/\/ 1. Create a resolved mutable document based on the current saved document\r\n    let resolved = currentDoc.toMutable()\r\n    \r\n    \/\/ 2. Add the additional properties that don't already exist\r\n    for key in newDoc.keys {\r\n        if !resolved.contains(key) {\r\n            resolved.setValue(newDoc.value(forKey: key), forKey: key)\r\n        }\r\n    }\r\n    return resolved\r\n}<\/code><\/pre>\n<ul>\n<li><strong>Option 2:<\/strong>\u00a0<strong>Force your save to win<\/strong><\/li>\n<\/ul>\n<p>This option is effectively the same as the default concurrency policy of \u201cwrites always win\u201d. Except that in this case, you examine the contents of the currently saved document and then make a determination on whether to force a save using a <code>saveDocument<\/code>.<br \/>\nNote that you could still run the risk of a race condition in that the document could be updated again before you save it.<\/p>\n<pre><code class=\"swift\">do {\r\n    if try db.saveDocument(docToSave, concurrencyControl: .failOnConflict) {\r\n        \/\/ save was a success. docToSave is the new saved revision. Proceed as usual\r\n    }\r\n    else {\r\n        \/\/ Failure on save with failOnConflict mode\r\n        \/\/ Handle conflict appropriately\r\n        if let currDoc = db.document(withID: docToSave.id) {\r\n            \/\/ Option 2: Examine contents of current saved version of doc\r\n            \/\/ Force write of document\r\n            try db.saveDocument(docToSave)\r\n        }\r\n        else {\r\n            \/\/ Doc was deleted.\r\n            \/\/ Option 2: Attempt to do a force write of document to override the delete\r\n            try db.saveDocument(docToSave)\r\n        }\r\n    }\r\n}\r\ncatch {\r\n    print(\"Some other error in saving \\(error)\")\r\n}<\/code><\/pre>\n<ul>\n<li><strong>Option 3:<\/strong>\u00a0<strong>Skip the save<\/strong><\/li>\n<\/ul>\n<p>In this case, you could examine the contents of the currently saved document and then determine that you would rather keep the currently saved version of the document.<\/p>\n<pre><code class=\"swift\">do {\r\n    let docToSave = MutableDocument(id: \"docId\")\r\n    if !(try db.saveDocument(docToSave, concurrencyControl: .failOnConflict)) {\r\n        \/\/ Fetch the current saved version of doc\r\n        if let currDoc = db.document(withID: docToSave.id) {\r\n            \/\/ Option 3 : Examine contents of doc\r\n            \/\/ Current saved doc looks fine. Do nothing\r\n        }\r\n        else {\r\n            \/\/ Doc was deleted. Handle appropriately\r\n        }\r\n    }\r\n    else {\r\n        \/\/ save was a success. docToSave is the new saved revision. Proceed as usual\r\n    }\r\n}\r\ncatch {\r\n    print(\"Some other error in saving \\(error)\")\r\n}\r\n<\/code><\/pre>\n<h3 id=\"implicationsoncreatingdocumentswithsameid\">Implications on Creating Documents with the same Id<\/h3>\n<p>Since the default conflict resolution policy on <code>saveDocument<\/code> is that the last write always wins, if you attempt to create a document again with a <code>docId<\/code> that already exists in the database, it will go ahead and update the existing document by adding a new revision to it.<\/p>\n<p>Hence, if you want to ensure that you do not inadvertently update an existing document, you must specify the &#8220;<em>ConcurrenyControl<\/em> argument with <code>failOnConflict<\/code>. This will then return an error that you can handle appropriately.<\/p>\n<p>This is very much similar to the Option 3 specified earlier except that in this case, you don\u2019t have to examine the current contents of the document. A conflict failure implies that a document with Id already exists.<\/p>\n<p>This is an example in Swift<\/p>\n<pre><code class=\"swift\">do {\r\n    let docToSave = MutableDocument(id: \"docId\")\r\n    if !(try db.saveDocument(docToSave, concurrencyControl: .failOnConflict)) {\r\n        \/\/ Document with Id already exists. Handle appropriately\r\n    }\r\n    else {\r\n        \/\/ save was a success. docToSave is the new saved revision. Proceed as usual\r\n    }\r\n}\r\ncatch {\r\n    print(\"Some other error in saving \\(error)\")\r\n}<\/code><\/pre>\n<h3 id=\"conflictfreemodeinsyncgateway2.0\">Conflict-Free Mode in Sync Gateway 2.0<\/h3>\n<p>In this mode, the sync gateway rejects revisions that cause a conflict with an HTTP 409 Error, effectively ensuring that there are no conflicting revisions in the database. Conflicts are handled on the client-side during a pull replication.<\/p>\n<h4 id=\"pushreplication\">Push Replication<\/h4>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/01\/conflict-free-push.png\" alt=\"\" \/><\/figure>\n<ol>\n<li>The client pushes up the revision changes to Sync Gateway.<\/li>\n<li>Sync Gateway detects that the incoming revision is in conflict with the current saved revision on the server (i.e. the incoming revision\u2019s ancestor is not the active revision on the server)<\/li>\n<li>Sync Gateway rejects the revision change with a <em>409 Error<\/em>. Couchbase Lite does not really do anything other than log the error. The conflict is subsequently resolved during a pull replication.<\/li>\n<\/ol>\n<h4 id=\"pullreplication\">Pull Replication<\/h4>\n<p>During a pull replication, if the client detects a conflict, the conflict is resolved using the following deterministic criteria<\/p>\n<ul>\n<li>Deletes always win. An example of this case is as shown below.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/03\/deletes_always_win.png\" alt=\"\" \/><\/p>\n<ul>\n<li>The most recent change (highest <code>generation ID<\/code>) wins or the revision with max <code>revID<\/code> wins if the generations are the same. i.e. &#8211; the revID that sorts higher in a simple ASCII comparison. An example of this is shown below.<\/li>\n<\/ul>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/03\/most_recent_writes_win.png\" alt=\"\" \/><\/figure>\n<p>&nbsp;<\/p>\n<p>Next, we examine the cases during Pull Replication.<\/p>\n<p><strong>Server Branch is the Winner<\/strong><\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/03\/conflict-free-pull-server-winner.png\" alt=\"\" \/><\/figure>\n<ol>\n<li>Client pulls the revision changes from the Sync Gateway<\/li>\n<li>Client detects that the incoming revision is in conflict with the current saved revision (i.e. the incoming revision and saved revision share a common parent)<\/li>\n<li>Client calls the conflict resolver function which determines the winner between the current saved revision and the server revision.\n<ol>\n<li>Since the incoming revision (<code>Rev2-B<\/code>) from the server is more recent than the local revision (<code>Rev2-A<\/code>), the server revision is selected as the winner. Note that this would also be the case if the revision on the server was deleted.<\/li>\n<\/ol>\n<\/li>\n<li>The server branch is grafted to the local revision tree (and the local branch is tombstoned)<\/li>\n<li>Subsequently, when changes are pushed to the server, there will be no conflicts and the server syncs up with the client-side.<\/li>\n<\/ol>\n<h5 id=\"localbranchisthewinner\"><strong>Local Branch is the Winner<\/strong><\/h5>\n<figure><img decoding=\"async\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/03\/conflict-free-pull-local-winner.png\" alt=\"\" \/><\/figure>\n<ol>\n<li>Client pulls the revision changes from the Sync Gateway<\/li>\n<li>Client detects that the incoming revision is in conflict with the current saved revision (i.e. the incoming revision and saved revision share a common parent)<\/li>\n<li>Client calls the conflict resolver function which determines the winner between the current saved revision and the server revision.\n<ol>\n<li>Since the local revision (<code>Rev2-B<\/code>) is the more recent than the incoming server revision (<code>Rev2-A<\/code>), the local revision is selected as the winner. Note that this would also be the case if the revision on the local branch was deleted.<\/li>\n<\/ol>\n<\/li>\n<li>The server branch is grafted to the local revision tree and a new revision <code>Rev3<\/code> is added which corresponds to the contents of the winning revision, <code>Rev2-B<\/code><\/li>\n<li>Subsequently, when changes are pushed to the server, there will be no conflicts and the server syncs up with the client-side.<\/li>\n<\/ol>\n<p><strong>NOTE<\/strong>: As you have observed, conflicts are resolved on Couchbase Lite during a pull replication. The implication of this is that if the replicator is configured to only be a push replicator, then Couchbase Lite\u2019s view of the data will diverge from Sync Gateway\u2019s (since some of CBL\u2019s attempted writes would fail w\/ 409). Hence, if you foresee conflicts to occur, then it is recommended that the Couchbase Lite replicator be configured in push-pull mode when used in Conflict Free mode<\/p>\n<p>&nbsp;<\/p>\n<h3>Configuring Conflict-Free Mode on Sync Gateway<\/h3>\n<p>\u201cConflict Free\u201d mode on Sync Gateway is configurable through <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/2.0\/guides\/sync-gateway\/config-properties\/index.html#2.0\/databases-foo_db-allow_conflicts\">allow_conflicts<\/a>\u00a0property in the Sync Gateway configuration file. It must be set to &#8220;<em>false<\/em>&#8221; to enable conflict-free mode. It should also be noted that regardless of this property configuration, there will be no conflicting revisions added to the Sync Gateway when syncing with Couchbase Lite 2.0 clients. We discussed that earlier in the section on Replication. The &#8220;allow_conflicts&#8221; configuration only has implications for non 2.0 clients and REST API clients. The table below summarizes the implication<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-4867\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2018\/03\/allow_conflict.png\" alt=\"allow_conflicts_configuration\" width=\"501\" height=\"222\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/allow_conflict.png 501w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/allow_conflict-300x133.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/allow_conflict-20x9.png 20w\" sizes=\"auto, (max-width: 501px) 100vw, 501px\" \/><\/p>\n<h2 id=\"impactofconflictfreemodeondatabasesizes\">Impact of Conflict-Free mode on Database sizes<\/h2>\n<p>The impact of conflict resolution on database size was discussed in detail in our earlier post on <a href=\"https:\/\/www.couchbase.com\/blog\/database-sizes-and-conflict-resolution\/\">Managing database sizes<\/a>. In the system that allowed for conflicts, as conflicting revisions grow, the size of the revision tree can grow to impact the size of the database. So it was important to resolve conflicts in a timely fashion. Sync Gateway has a <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/current\/guides\/sync-gateway\/config-properties\/index.html#1.5\/databases-foo_db-revs_limit\"><code>revs_limit<\/code><\/a> property that determines the size of the revision tree. The <code>revs_limit<\/code> property defaults to 1000, which means that the metadata corresponding to the last 1000 revisions are stored in Sync Gateway before getting pruned away. While setting the <code>revs_limit<\/code> to a large value would negatively impact the database size, it was important not to set it to a very low value. It was important to maintain the metadata corresponding to the older revisions as they were needed to handle conflict resolution else you run the risk of having a forest of disconnected revision trees for a document. So the minimum permissible value of <code>revs_limit<\/code> is 20.<\/p>\n<p>However, with conflict-free mode, there is no real need to save the metadata corresponding to older revisions. This implies that the <code>revs_limit<\/code> could be just 1. This implies that only the latest\/active revision is stored. This brings big savings in database size.<\/p>\n<h2 id=\"acnowledgements\">Acknowledgments<\/h2>\n<p>Special thanks to <a href=\"https:\/\/github.com\/pasin\">Pasin Suriyentrakorn<\/a> from the Mobile Engineering team for his feedback on the Couchbase Lite sections, to <a href=\"https:\/\/github.com\/adamcfraser\">Adam Fraser<\/a>, also from the Mobile Engineering team, for his feedback on the Sync Gateway sections and to Daniel Petersen from the Mobile Engineering team for his feedback.<\/p>\n<h2 id=\"whatnext\">What Next<\/h2>\n<p>This blog post discussed how conflicts are automatically handled in Couchbase Mobile 2.0. You can download Couchbase Mobile 2.0 from our <a href=\"https:\/\/developer.couchbase.com\/documentation\/mobile\/2.0\/whatsnew.html\">downloads<\/a> page.<\/p>\n<p>If\u00a0you have questions or feedback, please leave a comment below or feel free to reach out to me at Twitter at\u00a0<a href=\"https:\/\/twitter.com\/rajagp\">@rajagp<\/a>\u00a0or email me at\u00a0<a href=\"mailto:priya.rajagopal@couchbase.com\">priya.rajagopal@couchbase.com<\/a>. \u00a0The\u00a0<a href=\"https:\/\/www.couchbase.com\/forums\/\">Couchbase Forums<\/a> are another great place to reach out with\u00a0questions.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Document conflicts can occur in distributed environments that support data synchronization, wherein a document can be updated concurrently by one or more writers. This is especially common in mobile environments where unreliable network connections may result in concurrent changes from [&hellip;]<\/p>\n","protected":false},"author":1423,"featured_media":10700,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,1821,7667,1810,2366,2201],"tags":[2178,1980,2004,1981],"ppma_author":[8948],"class_list":["post-4832","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-architecture","category-couchbase-lite","category-couchbase-mobile","category-sync-gateway","category-tools-sdks","tag-concurrency-control","tag-conflict-resolution","tag-couchbase-mobile-2-0","tag-mvcc"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Document Conflicts &amp; Resolution in Couchbase Mobile 2.0<\/title>\n<meta name=\"description\" content=\"This post discusses the fundamentals of how document conflicts are handled in Couchbase Mobile 2.0 using \u201cautomatic conflict resolution\u201d.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0\" \/>\n<meta property=\"og:description\" content=\"This post discusses the fundamentals of how document conflicts are handled in Couchbase Mobile 2.0 using \u201cautomatic conflict resolution\u201d.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-03-19T14:00:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T06:43:12+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1552\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Priya Rajagopal, Senior Director, Product Management\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@rajagp\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Priya Rajagopal, Senior Director, Product Management\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/\"},\"author\":{\"name\":\"Priya Rajagopal, Senior Director, Product Management\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c2da90e57717ee4970c48a87a131ac2c\"},\"headline\":\"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0\",\"datePublished\":\"2018-03-19T14:00:32+00:00\",\"dateModified\":\"2025-06-14T06:43:12+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/\"},\"wordCount\":2307,\"commentCount\":14,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png\",\"keywords\":[\"concurrency control\",\"conflict resolution\",\"couchbase mobile 2.0\",\"MVCC\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Architecture\",\"Couchbase Lite\",\"Couchbase Mobile\",\"Sync Gateway\",\"Tools &amp; SDKs\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/\",\"name\":\"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png\",\"datePublished\":\"2018-03-19T14:00:32+00:00\",\"dateModified\":\"2025-06-14T06:43:12+00:00\",\"description\":\"This post discusses the fundamentals of how document conflicts are handled in Couchbase Mobile 2.0 using \u201cautomatic conflict resolution\u201d.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png\",\"width\":1552,\"height\":628},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c2da90e57717ee4970c48a87a131ac2c\",\"name\":\"Priya Rajagopal, Senior Director, Product Management\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/4b50a54778b979d8c345b036ab138734\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g\",\"caption\":\"Priya Rajagopal, Senior Director, Product Management\"},\"description\":\"Priya Rajagopal is a Senior Director of Product Management at Couchbase responsible for developer platforms for the cloud and the edge. She has been professionally developing software for over 20 years in several technical and product leadership positions, with 10+ years focused on mobile technologies. As a TISPAN IPTV standards delegate, she was a key contributor to the IPTV standards specifications. She has 22 patents in the areas of networking and platform security.\",\"sameAs\":[\"https:\/\/x.com\/rajagp\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/priya-rajagopalcouchbase-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0","description":"This post discusses the fundamentals of how document conflicts are handled in Couchbase Mobile 2.0 using \u201cautomatic conflict resolution\u201d.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/","og_locale":"en_US","og_type":"article","og_title":"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0","og_description":"This post discusses the fundamentals of how document conflicts are handled in Couchbase Mobile 2.0 using \u201cautomatic conflict resolution\u201d.","og_url":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/","og_site_name":"The Couchbase Blog","article_published_time":"2018-03-19T14:00:32+00:00","article_modified_time":"2025-06-14T06:43:12+00:00","og_image":[{"width":1552,"height":628,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png","type":"image\/png"}],"author":"Priya Rajagopal, Senior Director, Product Management","twitter_card":"summary_large_image","twitter_creator":"@rajagp","twitter_misc":{"Written by":"Priya Rajagopal, Senior Director, Product Management","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/"},"author":{"name":"Priya Rajagopal, Senior Director, Product Management","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c2da90e57717ee4970c48a87a131ac2c"},"headline":"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0","datePublished":"2018-03-19T14:00:32+00:00","dateModified":"2025-06-14T06:43:12+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/"},"wordCount":2307,"commentCount":14,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png","keywords":["concurrency control","conflict resolution","couchbase mobile 2.0","MVCC"],"articleSection":["Best Practices and Tutorials","Couchbase Architecture","Couchbase Lite","Couchbase Mobile","Sync Gateway","Tools &amp; SDKs"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/","url":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/","name":"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png","datePublished":"2018-03-19T14:00:32+00:00","dateModified":"2025-06-14T06:43:12+00:00","description":"This post discusses the fundamentals of how document conflicts are handled in Couchbase Mobile 2.0 using \u201cautomatic conflict resolution\u201d.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2018\/03\/conflict-resolver-basics.png","width":1552,"height":628},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/document-conflicts-couchbase-mobile\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Document Conflicts &amp; Resolution in Couchbase Mobile 2.0"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/c2da90e57717ee4970c48a87a131ac2c","name":"Priya Rajagopal, Senior Director, Product Management","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/4b50a54778b979d8c345b036ab138734","url":"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g","caption":"Priya Rajagopal, Senior Director, Product Management"},"description":"Priya Rajagopal is a Senior Director of Product Management at Couchbase responsible for developer platforms for the cloud and the edge. She has been professionally developing software for over 20 years in several technical and product leadership positions, with 10+ years focused on mobile technologies. As a TISPAN IPTV standards delegate, she was a key contributor to the IPTV standards specifications. She has 22 patents in the areas of networking and platform security.","sameAs":["https:\/\/x.com\/rajagp"],"url":"https:\/\/www.couchbase.com\/blog\/author\/priya-rajagopalcouchbase-com\/"}]}},"authors":[{"term_id":8948,"user_id":1423,"is_guest":0,"slug":"priya-rajagopalcouchbase-com","display_name":"Priya Rajagopal, Senior Director, Product Management","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/acfb2349788955262cd069497a9e7bdb0e97c26326f2e55811e7c1174e9ef1be?s=96&d=mm&r=g","author_category":"","last_name":"Rajagopal, Senior Director, Product Management","first_name":"Priya","job_title":"","user_url":"","description":"Priya Rajagopal is a Senior Director of Product Management at Couchbase responsible for developer platforms for the cloud and the edge. She has been professionally developing software for over 20 years in several technical and product leadership positions, with 10+ years focused on mobile technologies. As a TISPAN IPTV standards delegate, she was a key contributor to the IPTV standards specifications. She has 22 patents in the areas of networking and platform security."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/4832","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/1423"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=4832"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/4832\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/10700"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=4832"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=4832"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=4832"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=4832"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}