{"id":22819668,"date":"2026-04-14T10:00:00","date_gmt":"2026-04-14T14:00:00","guid":{"rendered":"https:\/\/thenewstack.io\/?p=22819668"},"modified":"2026-04-13T17:16:56","modified_gmt":"2026-04-13T21:16:56","slug":"real-time-sync-engine","status":"publish","type":"post","link":"https:\/\/thenewstack.io\/real-time-sync-engine\/","title":{"rendered":"From clobbered drafts to real-time sync"},"content":{"rendered":"\n<p>Before writing the first line of code for <a href=\"https:\/\/docs.suga.app\/introduction\" type=\"link\" id=\"https:\/\/docs.suga.app\/introduction\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Suga<\/a>, we knew we eventually wanted multiplayer interactions, so that teams could collaborate on projects. However, with a long feature wishlist already, we figured we could defer it until later as &#8220;nice to have&#8221;. So instead, the first canvas implementation was built with basic last-write-wins conflict resolution.&nbsp;<\/p>\n\n\n\n<p>Unfortunately, Jye and I figured out the hard way that our assumption about conflict resolution was pretty naive. Using an early build of Suga, we started working in a shared project at the same time without realizing. I was adding a service, along with its Postgres database, config, env vars, and tweaking positions so the layout made sense. Jye was on the other side of the project, adding functions and coding up integrations.<\/p>\n\n\n\n<p>Changes get saved as a draft automatically as you work, so every time one of us moved a node or added a connection, the draft updated. However, because there was no merging, each save just replaced the entire draft with whatever the client had. My saves were silently overwriting Jye&#8217;s work, and his were overwriting mine. When Jye refreshed the browser tab, everything he&#8217;d built was gone, since I&#8217;d made the most recent change, the last draft write was mine. We do automatically track a project&#8217;s history, but only for deployed changes, so because none of this had been deployed yet, it was just lost.<\/p>\n\n\n\n<p>It made it obvious that last-write-wins for the entire canvas wasn&#8217;t going to work. Although we could have improved the situation with other locking\/conflict resolution techniques, we knew we wanted full multiplayer eventually, so real-time sync was the right choice.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-have-you-looked-at-sync-engines\">Have you looked at sync engines?<\/h2>\n\n\n\n<p>If you&#8217;re unfamiliar with sync engines, Jye got kind of obsessed with them last year and <a href=\"https:\/\/bytemash.net\/posts\/i-went-down-the-linear-rabbit-hole\/\" type=\"link\" id=\"https:\/\/bytemash.net\/posts\/i-went-down-the-linear-rabbit-hole\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">wrote a blog about it<\/a>. I&#8217;d also recently watched a <a href=\"https:\/\/www.youtube.com\/watch?v=_tHSAKVCJQo\" type=\"link\" id=\"https:\/\/www.youtube.com\/watch?v=_tHSAKVCJQo\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Syntax video<\/a> where they used Zero to build a competitive coding game, and the sync model clicked immediately. In our next standup, we both agreed we needed to drop other features and get this built.<\/p>\n\n\n\n<p>We ended up going with <a href=\"https:\/\/zero.rocicorp.dev\/\" type=\"link\" id=\"https:\/\/zero.rocicorp.dev\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Zero<\/a>, which is a sync engine from Rocicorp. Basically, every client gets a local SQLite database that stays in sync with our PostgreSQL on the server. Writes happen locally first, then are replayed on the server; if there&#8217;s a conflict, the server wins, and clients reconcile automatically.<\/p>\n\n\n\n<p>Why Zero and not something else? CRDT libraries like Yjs and Automerge are designed for document-style collaboration, things like text editors and drawing tools. Our <a href=\"https:\/\/thenewstack.io\/dont-let-time-series-data-break-your-relational-database\/\" data-wpil-monitor-id=\"3769\" class=\"local-link\">data is relational<\/a> Postgres rows, including some larger JSONB columns. Tools like ElectricSQL and PowerSync also sync Postgres, but Zero&#8217;s <a href=\"https:\/\/zero.rocicorp.dev\/docs\/mutators\" type=\"link\" id=\"https:\/\/zero.rocicorp.dev\/docs\/mutators\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">mutator<\/a> model gave us fine-grained control over conflict resolution for JSON values.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-two-kinds-of-changes\">Two kinds of changes<\/h2>\n\n\n\n<p>We realized early that not all changes are equal; some can be merged, some can&#8217;t, and some can tolerate last-write-wins. Figuring out which was which turned out to be the core design problem. The canvas is built on <a href=\"https:\/\/reactflow.dev\/\" type=\"link\" id=\"https:\/\/reactflow.dev\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">React Flow<\/a>, and every interaction that changes state goes through a Zero mutator.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>&#8220;Figuring out which was which turned out to be the core design problem.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"654\" src=\"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/43e36fed-11-1024x654.png\" alt=\"Diagram of interactions that change state, going through a Zero mutator.\" class=\"wp-image-22819671\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-granular-mutators\">Granular mutators<\/h3>\n\n\n\n<p>The canvas node positions are stored as a single JSON value for simplicity. What we want is when I drag a node, only that node&#8217;s position changes. If someone else drags a different node at the same time, both writes land cleanly, without conflict. If we somehow drag the same node simultaneously, the last write wins, since that&#8217;s fine for node positions where there&#8217;s no meaningful way to merge them and the data isn&#8217;t critical. If I place a node at (400, 200) and Jye places one at (600, 300), one of us will win.<\/p>\n\n\n\n<p>Here&#8217;s what that mutator looks like for node positions:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ntypescript\nexport const updateNodePosition = defineMutator(\n  z.object({ environmentId: z.string(), nodeId: z.string(), position: PositionSchema }),\n  async ({ tx, ctx, args: { environmentId, nodeId, position } }) =&gt; {\n    \/\/ Access check runs server-side only\n    if (tx.location === &quot;server&quot;) {\n      await verifyAccess(tx, environmentId, ctx.activeOrganizationId);\n    }\n\n    const env = await getEnvironment(tx, environmentId);\n\n    \/\/ Spread existing positions, overwrite just this node\n    await tx.mutate.environment.update({\n      id: environmentId,\n      canvasMetadata: {\n        ...env?.canvasMetadata,\n        nodePositions: {\n          ...env?.canvasMetadata?.nodePositions,\n          &#x5B;nodeId]: position,\n        },\n      },\n    });\n  },\n);\n<\/pre><\/div>\n\n\n<p>The spread is the key part: we read the current positions and overwrite only the one node. On the client, this reads from local cache; on the server, it reads from the database. Both run the same function, but the server&#8217;s view is authoritative.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>&#8220;The spread is the key part: we read the current positions and overwrite only the one node&hellip; the server&#8217;s view is authoritative.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>A similar pattern applies to infrastructure changes, which is what fixed our clobbering problem. When I add a service, the mutator reads the current compute array, appends mine, and writes it back. If someone else adds a function at the same time, their mutator does the same. The server replays both, and the result has both changes.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ntypescript\nexport const addCompute = defineMutator(\n  z.object({\n    environmentId: z.string(),\n    compute: ComputeSchema,\n    position: PositionSchema.optional(),\n  }),\n  async ({ tx, ctx, args: { environmentId, compute, position } }) =&gt; {\n    \/\/ ... same access check pattern\n\n    const env = await getEnvironment(tx, environmentId);\n    const def = env?.draftDefinition;\n\n    \/\/ Read current computes, append the new one, write it back\n    const updatedDef: ProjectDefinition = {\n      version: &quot;v1&quot;,\n      computes: &#x5B;...def.computes, compute],\n      volumes: def.volumes,\n    };\n\n    await tx.mutate.environment.update({\n      id: environmentId,\n      draftDefinition: updatedDef,\n      \/\/ ... also sets node position on canvas if provided\n    });\n  },\n);\n<\/pre><\/div>\n\n\n<p>We considered <a href=\"https:\/\/thenewstack.io\/fireproof-uses-merkle-crdts-to-cut-database-latency\/\" type=\"link\" id=\"https:\/\/thenewstack.io\/fireproof-uses-merkle-crdts-to-cut-database-latency\/\" class=\"local-link\">using CRDTs<\/a> to merge these changes, but our data model would require significant work to decompose into CRDT-friendly structures. <a data-wpil-monitor-id=\"3768\" href=\"https:\/\/thenewstack.io\/custom-integrations-for-complex-scenarios-7-best-practices\/\" class=\"local-link\">Building a custom<\/a> CRDT would have added complexity without a clear win over last-write-wins for positions, or read-modify-write for computes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-bulk-mutators\">Bulk mutators<\/h3>\n\n\n\n<p>Some operations can&#8217;t be granular; for example, <code>undo<\/code> replaces the entire canvas with a previous snapshot. Deploy and discard do the same.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ntypescript\nexport const updateDraftAndCanvas = defineMutator(\n  z.object({ environmentId: z.string(), draftDefinition: ProjectDefinitionSchema, canvasMetadata: CanvasMetadataSchema }),\n  async ({ tx, ctx, args: { environmentId, draftDefinition, canvasMetadata } }) =&gt; {\n    \/\/ ... same access check\n\n    \/\/ No spread, no merge. Just replace everything.\n    await tx.mutate.environment.update({\n      id: environmentId,\n      draftDefinition,\n      canvasMetadata,\n    });\n  },\n);\n<\/pre><\/div>\n\n\n<p>There is currently no merging here; the snapshot wins. That&#8217;s the right tradeoff for undo, where the intent is &#8220;go back to exactly this state.&#8221;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-drizzle-as-the-schema-source-of-truth\">Drizzle as the schema source of truth<\/h2>\n\n\n\n<p>We use <a href=\"https:\/\/orm.drizzle.team\/\" type=\"link\" id=\"https:\/\/orm.drizzle.team\/\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Drizzle<\/a> as our ORM. Its schema definitions double as the source of truth for Zero&#8217;s sync schema.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ntypescript\nexport const environment = pgTable(&#039;environment&#039;, {\n  id: uuid(&#039;id&#039;).primaryKey().defaultRandom(),\n  projectId: uuid(&#039;project_id&#039;).references(() =&gt; project.id),\n  canvasMetadata: jsonb(&#039;canvas_metadata&#039;).$type&amp;lt;CanvasMetadata&gt;(),\n  draftDefinition: jsonb(&#039;draft_definition&#039;)\n    .default(InitialProjectDefinition)\n    .$type&amp;lt;ProjectDefinition&gt;(),\n  \/\/ ...\n});\n<\/pre><\/div>\n\n\n<p>Two JSONB columns hold the collaborative state: <code>canvasMetadata<\/code> for positions and sticky notes, <code>draftDefinition<\/code> for the infrastructure graph. The alternative would be to normalize into separate tables, which would give zero row-level diffs. We chose JSONB for now because it&#8217;s simpler and the mutator-level merge gives us enough control. If we hit scaling issues, normalizing is the obvious next step.<\/p>\n\n\n\n<p>A few gotchas we hit:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>JSONB is the replication unit, and Zero doesn&#8217;t diff inside the JSON, which is why the granular mutators do that spread pattern.<\/li>\n\n\n\n<li>If you forget to regenerate after a schema migration, the client silently misses new columns without errors, resulting in missing data.<\/li>\n\n\n\n<li>We had to write custom scripts to create Zero publications and a filter. Getting the publication config right took several rounds of tuning what gets replicated and what doesn&#8217;t.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-nanostores-for-local-state\">Nanostores for local state<\/h2>\n\n\n\n<p>Zero handles synced state, but some state belongs only on the client, such as user-specific undo history; for that, we use Nanostores. These stores are really just a read-only way to consume Zero data, where Zero handles all mutations and then syncs with the store. <a href=\"https:\/\/github.com\/nanostores\/nanostores\" type=\"link\" id=\"https:\/\/github.com\/nanostores\/nanostores\" class=\"ext-link\" rel=\"external nofollow\" onclick=\"this.target=&#039;_blank&#039;;\">Nanostores<\/a> is lightweight and handles the globally accessible state part cleanly.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ntypescript\nexport const $nodePositions = map&amp;lt;Record&amp;lt;string, Position&gt;&gt;({});\nexport const $stickyNotes = atom&amp;lt;StickyNote&#x5B;]&gt;(&#x5B;]);\nexport const $draftDef = atom&amp;lt;ProjectDefinition&gt;(InitialProjectDefinition);\nexport const $undoState = atom&amp;lt;UndoState&gt;({ past: &#x5B;], future: &#x5B;] });\n<\/pre><\/div>\n\n\n<p>For undo, we capture a full snapshot before each meaningful change and store it in a 20-item history stack. Undo restores the snapshot locally and fires a bulk mutator via Zero to sync it with other clients.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-works-locally-breaks-on-deploy\">Works locally, breaks on deploy<\/h2>\n\n\n\n<p>Getting Zero running locally went well enough; we just run a compose file for local dev, and the CLI auto-generates the schema from Drizzle. I demoed it to the team, and everyone could see each other&#8217;s changes, nodes appearing in real time, the whole thing. It worked, and I was feeling good about it.<\/p>\n\n\n\n<p>We deployed to staging, and it broke instantly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-the-silent-401s\">The silent 401s<\/h3>\n\n\n\n<p>Our staging and preview deployments run with deployment protection enabled. Zero-cache runs as a separate server and needs to call <code>\/api\/zero\/query<\/code> and <code>\/api\/zero\/mutate<\/code> on the main application. Deployment protection was blocking those requests with 401s.<\/p>\n\n\n\n<p>The frustrating part was that in the browser, nothing looked obviously wrong. The failures were happening between Zero and our other endpoints, not in the browser&#8217;s network tab. I had to pull up the workload logs to see the actual errors stacking up. Once I saw them, the fix was adding the appropriate header to the query and mutation requests.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-the-cookie-problem\">The cookie problem<\/h3>\n\n\n\n<p>Zero uses cookie-based auth by default, and our preview and staging environments generate new temporary URLs for every PR. Cookies are scoped to a domain, and with a new domain per preview deployment, cookie auth was basically impossible to get working reliably.<\/p>\n\n\n\n<p>For local and staging environments, we pass the session token directly via the <code>auth<\/code> prop on the <code>ZeroProvider<\/code> component instead of relying on cookies, while production still uses cookies. It&#8217;s a small split in the auth path, but it was a reliable way to support the way we use preview deployments.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-it-s-live-now\">It&#8217;s live now<\/h2>\n\n\n\n<p>Since adding Zero for sync and conflict resolution, Suga users can all work in the same project at the same time. If you have feedback on how we can improve your experience, reach out. We&#8217;re always looking for ways to improve.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>My colleague lost an afternoon of work because my auto-save overwrote his draft. That&#8217;s when we knew we needed a sync engine.<\/p>\n","protected":false},"author":2661,"featured_media":22819684,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[13672,10055,12853],"tags":[13137,12344],"coauthors":[13306],"class_list":["post-22819668","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-backend-development","category-software-development","category-typescript","tag-sponsor-nitric","tag-sponsored-post-contributed"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.8 (Yoast SEO v26.8) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>From clobbered drafts to real-time sync - The New Stack<\/title>\n<meta name=\"description\" content=\"How Suga used the Zero sync engine to fix data overwrites and enable real-time multiplayer collaboration for engineering teams.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/thenewstack.io\/real-time-sync-engine\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"From clobbered drafts to real-time sync\" \/>\n<meta property=\"og:description\" content=\"How Suga used the Zero sync engine to fix data overwrites and enable real-time multiplayer collaboration for engineering teams.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/thenewstack.io\/real-time-sync-engine\/\" \/>\n<meta property=\"og:site_name\" content=\"The New Stack\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/thenewstack\" \/>\n<meta property=\"article:published_time\" content=\"2026-04-14T14:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1920\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"David Moore\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@thenewstack\" \/>\n<meta name=\"twitter:site\" content=\"@thenewstack\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"David Moore\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/\"},\"author\":{\"name\":\"David Moore\",\"@id\":\"https:\/\/thenewstack.io\/#\/schema\/person\/519637808a0c133e5a78c6e32e7fc2ef\"},\"headline\":\"From clobbered drafts to real-time sync\",\"datePublished\":\"2026-04-14T14:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/\"},\"wordCount\":1426,\"publisher\":{\"@id\":\"https:\/\/thenewstack.io\/#organization\"},\"image\":{\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg\",\"keywords\":[\"nitric\",\"post-contributed\"],\"articleSection\":[\"Backend development\",\"Software Development\",\"TypeScript\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/\",\"url\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/\",\"name\":\"From clobbered drafts to real-time sync - The New Stack\",\"isPartOf\":{\"@id\":\"https:\/\/thenewstack.io\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg\",\"datePublished\":\"2026-04-14T14:00:00+00:00\",\"description\":\"How Suga used the Zero sync engine to fix data overwrites and enable real-time multiplayer collaboration for engineering teams.\",\"breadcrumb\":{\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/thenewstack.io\/real-time-sync-engine\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/#primaryimage\",\"url\":\"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg\",\"contentUrl\":\"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg\",\"width\":2560,\"height\":1920,\"caption\":\"A minimalist vector illustration of two fencers in a duel, serving as an artistic metaphor for data conflict resolution and real-time synchronization in collaborative software development.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/thenewstack.io\/real-time-sync-engine\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/thenewstack.io\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"From clobbered drafts to real-time sync\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/thenewstack.io\/#website\",\"url\":\"https:\/\/thenewstack.io\/\",\"name\":\"The New Stack\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/thenewstack.io\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/thenewstack.io\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/thenewstack.io\/#organization\",\"name\":\"The New Stack\",\"url\":\"https:\/\/thenewstack.io\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/thenewstack.io\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/cdn.thenewstack.io\/media\/2021\/11\/a9fbec84-the-new-stack-logo-rgb-screen.png\",\"contentUrl\":\"https:\/\/cdn.thenewstack.io\/media\/2021\/11\/a9fbec84-the-new-stack-logo-rgb-screen.png\",\"width\":1032,\"height\":128,\"caption\":\"The New Stack\"},\"image\":{\"@id\":\"https:\/\/thenewstack.io\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/thenewstack\",\"https:\/\/x.com\/thenewstack\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/thenewstack.io\/#\/schema\/person\/519637808a0c133e5a78c6e32e7fc2ef\",\"name\":\"David Moore\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/thenewstack.io\/#\/schema\/person\/image\/e73b23b9dab3fc0d8cb69df7f4f19243\",\"url\":\"https:\/\/thenewstack.io\/wp-content\/uploads\/2023\/11\/aa54bd50-cropped-734146d4-david-moore-96x96.jpg\",\"contentUrl\":\"https:\/\/thenewstack.io\/wp-content\/uploads\/2023\/11\/aa54bd50-cropped-734146d4-david-moore-96x96.jpg\",\"caption\":\"David Moore\"},\"description\":\"David Moore, head of engineering at Nitric, is a skilled software architect. He specializes in innovative product development and open source software solutions. With a strong record of spearheading major fintech and government projects, David has led UX framework development, mentored teams and established best practices. Outside of work, David enjoys live music, football, hiking and exploring the stunning beaches of Sydney Australia.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/david-moore-5b117266\/\"],\"url\":\"https:\/\/thenewstack.io\/author\/david-moore\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"From clobbered drafts to real-time sync - The New Stack","description":"How Suga used the Zero sync engine to fix data overwrites and enable real-time multiplayer collaboration for engineering teams.","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:\/\/thenewstack.io\/real-time-sync-engine\/","og_locale":"en_US","og_type":"article","og_title":"From clobbered drafts to real-time sync","og_description":"How Suga used the Zero sync engine to fix data overwrites and enable real-time multiplayer collaboration for engineering teams.","og_url":"https:\/\/thenewstack.io\/real-time-sync-engine\/","og_site_name":"The New Stack","article_publisher":"https:\/\/www.facebook.com\/thenewstack","article_published_time":"2026-04-14T14:00:00+00:00","og_image":[{"width":2560,"height":1920,"url":"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg","type":"image\/jpeg"}],"author":"David Moore","twitter_card":"summary_large_image","twitter_creator":"@thenewstack","twitter_site":"@thenewstack","twitter_misc":{"Written by":"David Moore","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/#article","isPartOf":{"@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/"},"author":{"name":"David Moore","@id":"https:\/\/thenewstack.io\/#\/schema\/person\/519637808a0c133e5a78c6e32e7fc2ef"},"headline":"From clobbered drafts to real-time sync","datePublished":"2026-04-14T14:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/"},"wordCount":1426,"publisher":{"@id":"https:\/\/thenewstack.io\/#organization"},"image":{"@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/#primaryimage"},"thumbnailUrl":"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg","keywords":["nitric","post-contributed"],"articleSection":["Backend development","Software Development","TypeScript"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/","url":"https:\/\/thenewstack.io\/real-time-sync-engine\/","name":"From clobbered drafts to real-time sync - The New Stack","isPartOf":{"@id":"https:\/\/thenewstack.io\/#website"},"primaryImageOfPage":{"@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/#primaryimage"},"image":{"@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/#primaryimage"},"thumbnailUrl":"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg","datePublished":"2026-04-14T14:00:00+00:00","description":"How Suga used the Zero sync engine to fix data overwrites and enable real-time multiplayer collaboration for engineering teams.","breadcrumb":{"@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/thenewstack.io\/real-time-sync-engine\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/#primaryimage","url":"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg","contentUrl":"https:\/\/cdn.thenewstack.io\/media\/2026\/04\/01de0576-greg-daines-rbjxexj2iqk-unsplash-scaled.jpg","width":2560,"height":1920,"caption":"A minimalist vector illustration of two fencers in a duel, serving as an artistic metaphor for data conflict resolution and real-time synchronization in collaborative software development."},{"@type":"BreadcrumbList","@id":"https:\/\/thenewstack.io\/real-time-sync-engine\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/thenewstack.io\/"},{"@type":"ListItem","position":2,"name":"From clobbered drafts to real-time sync"}]},{"@type":"WebSite","@id":"https:\/\/thenewstack.io\/#website","url":"https:\/\/thenewstack.io\/","name":"The New Stack","description":"","publisher":{"@id":"https:\/\/thenewstack.io\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/thenewstack.io\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/thenewstack.io\/#organization","name":"The New Stack","url":"https:\/\/thenewstack.io\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/thenewstack.io\/#\/schema\/logo\/image\/","url":"https:\/\/cdn.thenewstack.io\/media\/2021\/11\/a9fbec84-the-new-stack-logo-rgb-screen.png","contentUrl":"https:\/\/cdn.thenewstack.io\/media\/2021\/11\/a9fbec84-the-new-stack-logo-rgb-screen.png","width":1032,"height":128,"caption":"The New Stack"},"image":{"@id":"https:\/\/thenewstack.io\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/thenewstack","https:\/\/x.com\/thenewstack"]},{"@type":"Person","@id":"https:\/\/thenewstack.io\/#\/schema\/person\/519637808a0c133e5a78c6e32e7fc2ef","name":"David Moore","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/thenewstack.io\/#\/schema\/person\/image\/e73b23b9dab3fc0d8cb69df7f4f19243","url":"https:\/\/thenewstack.io\/wp-content\/uploads\/2023\/11\/aa54bd50-cropped-734146d4-david-moore-96x96.jpg","contentUrl":"https:\/\/thenewstack.io\/wp-content\/uploads\/2023\/11\/aa54bd50-cropped-734146d4-david-moore-96x96.jpg","caption":"David Moore"},"description":"David Moore, head of engineering at Nitric, is a skilled software architect. He specializes in innovative product development and open source software solutions. With a strong record of spearheading major fintech and government projects, David has led UX framework development, mentored teams and established best practices. Outside of work, David enjoys live music, football, hiking and exploring the stunning beaches of Sydney Australia.","sameAs":["https:\/\/www.linkedin.com\/in\/david-moore-5b117266\/"],"url":"https:\/\/thenewstack.io\/author\/david-moore\/"}]}},"_links":{"self":[{"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/posts\/22819668","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/users\/2661"}],"replies":[{"embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/comments?post=22819668"}],"version-history":[{"count":8,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/posts\/22819668\/revisions"}],"predecessor-version":[{"id":22819685,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/posts\/22819668\/revisions\/22819685"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/media\/22819684"}],"wp:attachment":[{"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/media?parent=22819668"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/categories?post=22819668"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/tags?post=22819668"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/thenewstack.io\/wp-json\/wp\/v2\/coauthors?post=22819668"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}