Building a multiplayer podcast editor with Automerge

asolove1 pts0 comments

Building a multiplayer podcast editor with Automerge — Adam Solove Adam Solove<br>Blog/UI engineering<br>10 Jun 2026

Building a multiplayer podcast editor with Automerge<br>Experience report of building a complex collaborative UI on top of a sync and versioning engine

▶ Contents Contents<br>Context<br>Working with Automerge<br>Data modeling for multiplayer<br>Implementing list re-order<br>Document history<br>Text and marks<br>What’s next<br>About me<br>Anticipated questions<br>What about the audio data?<br>Why build a server and browser UI, not a local-first app?<br>Is Automerge secure and web-scale? Should I use it in my startup?<br>Is Automerge better than … ?

By Adam Solove · Published 10 Jun 2026 · Reading time 16 min<br>Nine years ago, I wrote What are the important problems in UI engineering? Real-time multiplayer data synchronization was the most important but hardest one, requiring expertise, corporate spending, and some design tradeoffs to get right.

Today, you can just build multiplayer user interfaces for hobby projects, using tools that are one npm install away. My favorite is Automerge, an awesome piece of software for building data models that are local-first, multiplayer-safe, and versioned.

This post describes building a fairly novel UI on top of Automerge:

what just works

what extra bits of effort were required

my advice for getting started

Fig. 1.#

Screenshot of Ducking in use, with the comments and effects panels open.

Aside: This post is an experience report, not a tutorial, so I highly recommend looking at Automerge’s homepage animation, the docs overview, and at least the first page of the tutorial to learn more about Automerge. From here on out, I’ll assume you have a basic idea of what it’s for.

Context

I spent the last few months building Ducking, a browser-based, multiplayer audio editor tailored for my partner’s podcast.

The previous blog post described the unique UI design and audio layout model that makes it a much more pleasant way to put together an episode. Those improvements made a single editor more effective.

But what we really wanted was a more collaborative workflow. It’s ridiculous that audio editing is stuck in a twenty-year-old world of single-player desktop apps and emailing files back and forth. We wanted to work together as easily as in Google Docs or Figma: one of us editing some clips, while the other fixed the transcript or tweaked the EQ settings. Plus we wanted modern collaboration tools: comments, history, and tracked changes.

I was able to build that, thanks to Automerge. You could too.

Working with Automerge

All of Ducking’s data, aside from the audio blobs, lives in Automerge documents.

The core pattern of working with Automerge will be familiar to any React developer. You fetch data with a hook, render it as you like, and dispatch asynchronous requests to change it. After the data changes, the hook triggers a re-render. This is very similar to React’s normal useState patterns. Automerge’s version just happens to also persist the data locally, maintain history, broadcast to collaborators, receive updates from the network, and resolve conflicts — all without the UI needing to know.

import { useDocument } from '@automerge/react'

type Episode = { title: string }

export function EpisodeEditor({ docUrl }) {<br>const [doc, changeDoc] = useDocumentEpisode>(docUrl)<br>if (!doc) return p>Loading…p>

return (<br><><br>input<br>value={doc.title}<br>onChange={(e) =><br>changeDoc((d) => { d.title = e.target.value })<br>/>

The data update operations look distinctly un-React-like. The API has you write imperative-looking code, which seems to be directly modifying objects and arrays. But they are not quite the native JS objects and arrays you are used to: they support fewer methods and don’t actually mutate the data immediately, instead they intercept their own mutations to turn into changelist items in the document history.

For simple purposes, Automerge just does what you need. But it isn’t magic. Its invariants don’t always match your desired semantics without careful design. This makes it very important to carefully consider the data model, so that:

most semantic user actions correspond to single operations provided by Automerge

separate user actions on related data have natural resolutions in terms of the invariants of the corresponding Automerge operations

stored canonical data is clearly separated from calculated derived data

To make this more concrete, let’s look at two examples from my experience building Ducking:

one case where I had to improve the data model to get the right behavior

another case where Automerge didn’t provide the guarantees I needed, so I had to work around it

Data modeling for multiplayer

In Ducking’s data model, a clip is a window that plays back part of an underlying, immutable audio source. It knows which part of the audio to play, can apply effects to transform the audio, and holds an appropriate amount of space in the project timeline.

The most common effect is for the clip to...

automerge data multiplayer building audio from

Related Articles