[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"guide-how-to-keep-two-systems-in-sync-without-corrupting-either::en":3,"guide-related-how-to-keep-two-systems-in-sync-without-corrupting-either::en":17},{"slug":4,"title":5,"excerpt":6,"body":7,"meta_title":5,"meta_description":8,"keywords":9,"category":15,"published_at":16,"updated_at":16},"how-to-keep-two-systems-in-sync-without-corrupting-either","How to Keep Two Systems in Sync Without Corrupting Either","Two copies of the same record will disagree eventually, and the disagreement is usually silent. Deciding who owns which field, stopping updates echoing between systems, moving deletes safely, and reconciling on a schedule instead of after an incident.","\u003Ch2>The problem is two copies, not one connection\u003C\u002Fh2>\n\u003Cp>Wiring two systems together is a morning's work. Keeping them agreeing for a year is a different job, and it is the one this guide is about. Once the same customer, order or contact exists in two places you own the difference between them, and it grows quietly: nothing errors, both systems look healthy, and one of them is wrong.\u003C\u002Fp>\n\u003Cp>This is not about the other side changing its API underneath you, which is its own problem, and it is not about which automation tool to build in. Assume the connection works and the endpoints are stable. The question here is what happens to the data.\u003C\u002Fp>\n\u003Ch2>Decide who owns each field, not each record\u003C\u002Fh2>\n\u003Cp>Record-level ownership is the answer teams reach for first, and it rarely survives contact with the business. In practice the marketing system owns the subscription preference, billing owns the plan, support owns the last conversation, and all three hold a copy of the email address. Write ownership down field by field, because the argument only gets harder as data accumulates on both sides.\u003C\u002Fp>\n\u003Cp>Where a field genuinely has two writers, choose a rule and say it out loud. Last write wins is a legitimate choice, but it is a choice: it depends on clocks you do not control and it silently discards one of the two edits. The alternative considered less often than it deserves is to refuse to decide — keep both values and put the conflict in front of a person. Most systems produce far fewer real conflicts than teams fear, and a handful of flagged rows a week is cheaper than the corruption a wrong automatic rule manages in the same week.\u003C\u002Fp>\n\u003Ch2>One direction is a pipeline; two directions is a loop\u003C\u002Fh2>\n\u003Cp>A one-way sync behaves like a pipeline. A two-way sync introduces a hazard belonging to neither system on its own: a change you write into the second system produces a notification from it, your connector faithfully writes that back into the first, which notifies, and round it goes. Sometimes it settles. Sometimes it runs until a rate limit stops it, and the audit trail of both systems fills with an update every few seconds made by nobody.\u003C\u002Fp>\n\u003Cp>Breaking the loop takes a mechanism, not care. Mark the writes your own connector makes and ignore the notifications they cause — with a dedicated integration user whose changes you skip, or a recorded token from the write you just performed. Compare before writing and skip when the value is already what you intended to set; that one check removes most echoes cheaply. And accept that two-way costs more than two one-way syncs, which is a good reason to ask whether the second direction is needed at all.\u003C\u002Fp>\n\u003Ch2>Deletes are the part that goes wrong\u003C\u002Fh2>\n\u003Cp>Most syncs are built and tested on creates and updates, and meet deletes in production. The difficulty is that absence is ambiguous. A record missing from today's response might have been deleted, archived, moved outside the filter you query with, hidden because your permissions changed, or simply absent because a page of results failed to load. Treating all of those as a deletion instruction is how a sync empties a table.\u003C\u002Fp>\n\u003Cp>Prefer an explicit signal over inferred absence: a deletion event, a status field, a tombstone the provider keeps for a while. Where you must infer, do it slowly — require the record to be missing from more than one complete pass, never act on a partial or errored fetch, and cap how many deletions a single run may perform, because a run proposing to remove half the table is a bug rather than a busy day.\u003C\u002Fp>\n\u003Cp>Decide separately what a deletion on one side should even mean on the other. Frequently it is not \"delete\": unsubscribing a contact in one system rarely means erasing them from the system of record. Soft-delete on your side, keep what you are obliged to keep, and remember that the one case where propagation must be real and prompt is an erasure request, which is a legal obligation rather than a sync preference.\u003C\u002Fp>\n\u003Ch2>Incremental sync drifts, so reconcile on a schedule\u003C\u002Fh2>\n\u003Cp>Every incremental sync loses things. A webhook is not delivered, a job dies between the read and the write, a record is edited at the moment your cursor passes it, an update lands with a timestamp just before the watermark you saved. Each is rare. Over months, at volume, all of them happen, and none announce themselves.\u003C\u002Fp>\n\u003Cp>The remedy is a full comparison that runs on a schedule, not one that runs after somebody notices. Start cheap: counts on both sides, then counts per segment, then a checksum over the fields you care about, and only fetch the differing records in detail. Report drift as a number you watch over time rather than an incident you declare — a small steady figure is the normal condition of a working sync, and the useful alarm is a change in its shape, not the existence of a difference. Repair automatically only towards a field with a clear owner: mending a two-writer field with the rule that produced the drift turns a discrepancy into a loop.\u003C\u002Fp>\n\u003Ch2>Backfills behave differently from the steady state\u003C\u002Fh2>\n\u003Cp>The first load is not the ongoing sync running faster. It usually goes through different endpoints with different limits, arrives without meaningful ordering, and runs for hours alongside a live stream of changes to the same records — so the interesting failure is the collision, where the backfill writes an old version over a newer change that arrived while it was running and the data appears to travel quietly backwards. Make every write idempotent and keyed on the source identifier rather than on arrival order, refuse to overwrite a record with a version older than the one you hold, checkpoint progress so an interrupted run resumes instead of restarting, and do the first one against a copy, because mistakes at this stage are made at volume.\u003C\u002Fp>\n\u003Ch2>Make disagreement visible instead of resolving it invisibly\u003C\u002Fh2>\n\u003Cp>The worst outcome is not a sync that fails; it is one that succeeds at doing something wrong while every dashboard stays green. Anything your connector could not apply — a rejected write, a conflict, an unrecognised value, a record it skipped — has to land somewhere a person will look, with enough context to act on and a way to retry once the cause is fixed. A dead letter queue nobody opens is an outage with better manners.\u003C\u002Fp>\n\u003Cp>Two figures make the state of a sync legible: how far behind it is right now, and how many records currently disagree. Show them where whoever owns the data will see them, not only in an engineering dashboard, because the person who can tell you which value is correct is rarely the person watching the queue depth.\u003C\u002Fp>","Keeping two systems in sync: assign ownership field by field, break echo loops, handle deletes explicitly, reconcile on a schedule, and surface conflicts to people.",[10,11,12,13,14],"two-way sync","data reconciliation","sync loop","delete propagation","system integration","how-to","2026-09-03T03:30:02+00:00",[18,23,27,31,36,41],{"slug":19,"title":20,"excerpt":21,"updated_at":22},"ai-tool-pricing-models-seat-vs-usage-vs-credits","AI Tool Pricing Models: Seat-Based vs Usage-Based vs Credits","The three common ways AI tools charge — per seat, per usage, and by credits — and how to reason about which one will actually be cheaper for the way your team works.","2026-08-05T14:32:26+00:00",{"slug":24,"title":25,"excerpt":26,"updated_at":22},"how-ai-image-generators-differ-diffusion-vs-the-rest","How AI Image Generators Differ: Diffusion vs the Rest, in Plain Terms","A non-technical explanation of how AI image generators work, why the diffusion approach became dominant, and what practical differences to expect between tools.",{"slug":28,"title":29,"excerpt":30,"updated_at":22},"how-to-automate-your-workflow-without-code","How to Automate Your Workflow Without Code","A practical sequence for building automations that survive: picking the right process, mapping it before touching a tool, and handling the failure cases that break most first attempts.",{"slug":32,"title":33,"excerpt":34,"updated_at":35},"how-to-build-a-chatbot-without-coding","How to Build a Chatbot Without Coding","A practical route to a working chatbot using no-code tools: deciding scope, connecting your own content, handling the questions it cannot answer, and knowing what it will cost.","2026-08-05T14:32:27+00:00",{"slug":37,"title":38,"excerpt":39,"updated_at":40},"how-to-build-an-evaluation-set-that-does-not-go-stale","How to Build an Evaluation Set That Does Not Go Stale","Most evaluation sets are assembled once, from whatever was easy to collect, and then quietly stop representing the work. How to build one from failures you already have, keep it fed from production, protect it from the system it measures, and know when it has expired.","2026-09-09T03:30:02+00:00",{"slug":42,"title":43,"excerpt":44,"updated_at":45},"how-to-change-a-prompt-without-breaking-production","How to Change a Prompt Without Breaking Production","Prompts get edited in a text box and shipped in seconds, which is why they break things quietly: no compiler, no stack trace, no obvious moment of failure. Give them the release discipline code gets.","2026-08-24T03:30:02+00:00"]