An old browser tab should not quietly overwrite somebody else’s work. If two people open the same record, the second person to save may be submitting a perfectly valid form based on information that is no longer current. Validation will happily accept it. The person whose changes disappear will be rather less happy.
For a record edited as a whole, I like an explicit version number. The client reads version 7 and sends that version back with its changes. The database update checks the version and increments it in the same statement. Here is the basic shape in PostgreSQL, assuming an integer version column:
UPDATE projects
SET name = $1,
version = version + 1
WHERE id = $2
AND version = $3
RETURNING id, name, version;
If another writer has already moved the record to version 8, this update changes no rows. PostgreSQL’s Read Committed behaviour also matters when the writes overlap: after waiting for a concurrent updater to commit, it checks the condition against the updated row. The check belongs inside the write. Reading the version, comparing it in application code and then running an unconditional update leaves a gap.
That query is the concurrency part, not the entire endpoint. Keep the usual authorization checks and tenant boundary. A zero-row result needs handling according to the API’s rules, since a missing or inaccessible record can also produce no result. Every path that changes the protected record needs to maintain the version too, including background jobs and administrative tools.
The interface has work to do when there is a conflict. Keep the person’s unsaved changes, explain that the record changed and let them compare or reload. Automatically fetching the latest version and resubmitting the old form defeats the protection. It turns a conflict into a silent overwrite with an extra request.
This is useful where overwriting an edit would matter; a live counter may need a different operation entirely. I would test it with two clients reading the same version and then saving different values. One save should succeed, and the other should get a result the person can actually recover from.