Tidewater Docs v3.2

Guides / Conflict rules

Conflict rules

What happens when the same row changed on both sides since the last sync, and how to tell Tidewater which side wins.

A conflict is a row that has a newer updated_at on both the source and the replica than the timestamp of the last successful sync. Tidewater never guesses: without a rule it stops, lists the rows and exits with code 4.

Note

Rules apply per table. A table without a rule inherits the default rule, and if there is none, the sync stops on the first conflict.

#Declaring a rule

Rules live in tidewater.toml under the table they apply to. The rule names a winner and, optionally, columns that are merged instead of overwritten.

toml# tidewater.toml
[tables.orders]
conflict = "source"          # source | replica | newest | manual
merge = ["notes", "tags"]  # these columns are concatenated, not chosen

[tables.customers]
conflict = "newest"

Winners

ValueTypeMeaning
sourcedefaultstringThe source row overwrites the replica. The replica's version is kept in the journal for 30 days.
replicastringThe replica row is pushed back to the source. Needs write access on the source.
neweststringWhichever updated_at is later. Clocks must be within 5 s of each other or the sync refuses to run.
manualstringStop and write the conflicting pairs to .tidewater/conflicts/ for a person to resolve.

#Merging columns

Some columns should not have a winner. Free-text notes, tag lists and counters are better combined. The merge array names them; the rest of the row still follows the winner.

Careful

Merging a numeric column adds the two deltas since the last sync, not the two values. A counter that went 10 → 12 on one side and 10 → 15 on the other ends at 17, not 27.

#Seeing what a rule would do

Before trusting a rule on a large table, run the sync with --dry-run. It prints every conflict and the row that would win, and changes nothing.

shell$ tidewater sync --table orders --dry-run
3 conflicts in orders
  #4471  source wins  (replica changed 2 columns: status, notes → merged)
  #4480  source wins  (replica changed 1 column: status)
  #4502  source wins  (replica changed 4 columns)
dry run — nothing written

The same output is written to the journal on a real run, so the answer to "why does this row look like that" is always one tidewater log #4471 away.

Last edited 19 September 2026 · Edit this page