What Should Happen When Two People Edit the Same Thing at Once?
What Should Happen When Two People Edit the Same Thing at Once?
Something visible. The failure to avoid is the silent one, where the second person's save quietly erases the first person's work and nobody finds out for a week. Every acceptable answer either prevents the collision, detects it, merges it, or makes it recoverable.
Most SaaS products we look at handle this by accident rather than by design. The last save wins, there is no signal that anything was lost, and the support ticket arrives as "the system deleted my changes."
Here is the framework we use to decide which level of handling a given record actually needs, because full collaborative editing is expensive and usually unnecessary.
What Are the Four Levels of Handling a Conflict?
Prevent, detect, merge, and recover. They cost progressively more to build and they are not alternatives: a mature product uses different levels for different records.
Prevention means only one person can edit at a time, through a lock or a clear signal. Detection means both can edit, but the second save is refused with an explanation. Merging means both edits are kept and combined. Recovery means whatever happens, the previous version is retrievable.
Recovery is the only one that is close to mandatory. You can ship without prevention, detection or merging. You should not ship without a way to get the old value back.
When Is Locking the Right Answer?
When the record is structured, high stakes, and edited rarely by a small number of people. An invoice, a contract, a published pricing configuration, a payroll run.
For these, a lock is not a limitation, it is a reassurance. Showing "Priya is editing this, opened four minutes ago" tells the second person exactly what to do, which is to go and talk to Priya. That is better than any merge algorithm.
The thing that makes locks unpopular is bad implementation rather than the idea. Every lock needs an expiry, a visible owner, and a way for someone else to take it over with a warning. A lock held by a colleague who closed their laptop on Friday is worse than no lock at all.
How Do You Detect a Conflict Without Building Anything Clever?
Use a version token, and refuse writes that carry a stale one. This is standard HTTP behaviour and it is far simpler than teams expect.
MDN's documentation on the 412 status describes the mechanism plainly. A response carries an ETag, such as ETag followed by a hash of the content. A later write sends that same value back in an If-Match header. As MDN puts it, "if the hashes don't match, the document has been edited in-between and a 412 Precondition Failed error is thrown."
MDN describes the purpose of this as preventing "mid-air collisions," and that phrase is worth borrowing for your own product documentation because it describes the problem precisely.
The status code matters for your engineers. A 412 means the client's precondition failed, which is the optimistic concurrency case. A 409 Conflict is for a request that conflicts with the resource's state for business reasons, like a duplicate name. Using them correctly means your client code can respond differently to each.
What Should the User See When a Save Is Refused?
Their work, still on screen, plus what changed underneath them and who changed it. A refused save is only acceptable if nothing is lost in the refusing.
The version we recommend has four parts. A clear statement that someone else saved first. The name and time. A view of what differs between their version and the current one. And two buttons: keep mine, or take theirs.
The unacceptable version is an error message that dismisses the form. If your conflict dialog can lose the user's typing, the dialog is a worse bug than the conflict. That is a specific case of the broader argument in designing error messages people can act on.
Do You Actually Need Real-Time Merging?
Much less often than the current fashion suggests. Real-time collaborative editing is genuinely hard, and the honest engineering write-ups say so.
Evan Wallace, a Figma co-founder, explained in an October 2019 post that the team "didn't want to use operational transforms (a.k.a. OTs), the standard multiplayer algorithm," because "OTs were unnecessarily complex for our problem space." He describes OTs as "a great way of editing long text documents with low memory and performance overhead, but they are very complicated and hard to implement correctly."
Figma's own system is inspired by conflict-free replicated data types without being one. As the post says, "Figma isn't using true CRDTs though," because "since Figma is centralized (our server is the central authority), we can simplify our system by removing this extra overhead."
If a company whose entire product is multiplayer design chose the simpler path, a B2B SaaS tool with a settings page does not need a full merge engine.
What Is the Honest Limitation of the Simple Approach?
Per-field last writer wins, and you should document it rather than hide it. Figma's post is refreshingly direct about exactly this trade.
It describes the resolution as being that "the document will just end up with the last value that was sent to the server," an approach "similar to a last-writer-wins register." And it states the consequence without flinching: "this is why simultaneous editing of the same text value doesn't work in Figma. If the text value is B and someone changes it to AB at the same time as someone else changes it to BC, the end result will be either AB or BC but never ABC."
That is the model most products should adopt, and the lesson is to be as clear about it as Figma is. Per-field last writer wins is a reasonable design when different people usually touch different fields. It becomes unreasonable the moment two people are expected to write the same paragraph.
Why Does Field-Level Granularity Matter So Much?
Because it turns most conflicts into non-conflicts. If two people open the same customer record and one changes the phone number while the other changes the account owner, there is no conflict at all unless your product decided to treat the whole record as one value.
Whole-record saves are the single most common cause of avoidable data loss we see. The user changed one field. The form submitted forty. Thirty-nine of them silently overwrote whatever the other person had done.
Sending only changed fields fixes this, and it is not a research problem. It is a decision about what your update request contains.
Where Does Presence Fit In?
Before all of it, as the cheapest intervention available. Showing who else is looking at this record right now prevents more conflicts than any resolution strategy resolves.
Presence works because people are cooperative when informed. Two colleagues who can see each other on a record will coordinate in a message, and the conflict never happens. That is a far better outcome than an elegant merge.
Keep it honest, though. Presence that shows someone who left twenty minutes ago trains people to ignore it. Tie it to an actual live connection and clear it promptly when they go.
What Does Recovery Look Like If Everything Else Fails?
A version history with names and times, and a one click restore. Not a database backup, which is an engineer's tool. A user-facing history.
The bar is that any user who believes they lost work can find out what happened without contacting you. They should see that the field changed, when, from what, to what, and by whom, and be able to put it back.
This is the level we push hardest for in client work, because it is the only one that covers the failures you did not anticipate. It also doubles as an accountability record, which is a separate benefit we covered in designing an audit log people will read. If you build only one thing from this article, build this.
How Do You Decide Which Level Each Record Needs?
Ask two questions per record type. How often will two people genuinely touch this at the same time, and how bad is it if one edit is lost?
Rare and harmless: last writer wins per field, plus version history. This covers most settings, profiles and metadata. Rare and serious: locking, plus history. Contracts, billing configuration, anything with legal or financial consequence. Frequent and harmless: presence and field level saves. Shared internal notes and task boards. Frequent and serious: this is the only quadrant that justifies real merge work, and if you are in it, plan for it as a project rather than a feature.
Most products have records in three of those four quadrants and treat them all the same way. Sorting them takes an afternoon and tells you where to spend.
What Would We Build First?
Field level saves, version history, and presence, in that order. None of them require distributed systems expertise, and together they eliminate the great majority of real conflicts and make the remainder survivable.
Then add detection with a proper conflict dialog on the handful of records where a lost edit would genuinely hurt. Then, only if your usage data shows real simultaneous editing of the same text, consider merging.
The trap to avoid is starting at the end. Real-time collaboration is the most visible of these features and the least likely to be what your users need, and it is a lot of engineering to spend on a problem that presence would have prevented. If you are weighing up where to spend on this in your own product, we are happy to think it through with you at phoenix.studio.
Want a site that performs like this?
Tell us about your project. We will come back with a clear next step, no pressure.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Have a project like this?
Tell us where you want to go. We'll tell you how we'd get you there.