Recapping the first Local‑First conference in 15 minutes

Cover for Recapping the first Local‑First conference in 15 minutes

Local-first apps keep data locally, only using the cloud to synchronize data between machines (or peer‑to‑peer). This concept has become popular in recent years, and on May 30, 2024, the local‑first community came together for the inaugural Local-First Conference.

Andrey Sitnik, creator of Logux, our local-first system, visited this rapidly growing movement’s inaugural conference and wrote a quick recap summarizing the most compelling ideas.

Visitors of Local-First Conference 2024

An undercurrent of main ideas I heard again and again

First of all, some important ideas were reiterated across many talks:

  • Local-first is a spectrum, not a single feature. Some apps use peer-to-peer, others use a server with end-to-end encryption, while others still just have a partial cache on the client.
  • Local-first is the key to zero-latency UX. Having all data locally can provide a much better experience for your users.
  • Local-first boosts developer productivity. Moving all the networking code to the sync engine makes components smaller and decreases feature delivery time.
  • This concept has long been “ripening” in the community, and we’ve had local-first apps before. Really, this new term, “local-first”, is actually a “brand” centered around many old technologies and ideas (like CRDT, and so on) because now we have the browser API (like WASM and file system API to put SQLite/PostgreSQL to the browser) and the computer power to make it widely available.
  • Forming a community around the same values and principles, rather than a tech stack, is much more fun!
Schedule call

Irina Nazarova CEO at Evil Martians

Schedule call

A closer look at specific talks

I will highlight the most important ideas from the talks according to my subjective view. That said, it’s better to watch the full videos to more completely understand the speakers’ ideas within the proper context.

The past, present, and future of local-first

The first talk was from Martin Kleppmann, one of the originators of the term “local-first” in this famous essay from Ink & Switch.

He introduced a new definition of “local-first software”:

“In local-first architecture, the availability of another computer should never prevent you from working.”

He also explained what is not “local-first” (for him):

  1. If it’s local-only, it isn’t local-first.
  2. If it doesn’t work with Wi-Fi turned off, it isn’t local-first.
  3. If it doesn’t work if the app developer goes out of the business and shuts down their servers, it isn’t local-first.

That last requirement is very interesting, but it’s hard to implement this with real products.

In fact, this is why he thinks that, in the future, we should have a universal protocol to sync any local-first app. In this scenario, users could choose any server for their app.

However, the main challenge will be business models. Right now, users often pay an app’s creator for the ability to sync changes using the developer’s cloud.

Unexpected benefits of going local-first

Tuomas Artman, co-founder of Linear, explained the benefits of local-first to their business.

They began their startup by writing a sync engine: the app downloads the entire project’s data from the server and puts it into IndexedDB. Then, when the UI needs something from the model, they load it from IndexedDB and create the MobX observable.

Some takeaways:

  • Good sync engines provide many features for clients out of the box: UI performance, real-time, and offline support.
  • Local-first gives Linear high developer productivity because they don’t need to think about networking and server error processing.
  • You can write feature prototype without writing server code.
  • Local-first is good for infrastructure: it has extremely low resources requirements for scaling. 10,000 users on an $80/month server keep the CPU almost idle.

The why and how of building a local-first music app

Johannes Schickling, creator of the local-first podcast, explained how he created his music app Overtone. You may also see this app featured as a famous example of a local-first app with a near-zero latency UX.

Overtone demo from Johannes’s twitter

  1. Because the DOM is slow, he draws images and big lists/tables using canvas.
  2. He moved to Web Workers as much as possible.
  3. Creating a fast engine means creating your own DevTools (for instance, frame meters specific to your architecture).
  4. He stores data in SQLite using WASM to run it in the browser. The UI does not change data in the DB. Instead, it writes to the log, and both the DB and reactive signals read from the log and update the state.

This LiveStore engine will be available on GitHub.

End-to-end encryption demystified

Nik Graf, the creator secsync E2EE framework, explained end-to-end encryption:

  • Encrypted messages should not be just message + key. You need to add a non-secret nonce to the mix. This is a series of random bytes, but you use only one (the best way to generate new random bytes for every message). This prevents, for instance, restoring a key from duplicate messages (how many hi messages do you have in your chats?).
 { nonce: nonce, encrypted: encrypt(message, key, nonce) }

The URL’s #hash segment is a good way to send the secret key in the invite link because this part never goes to the server.

https://example.com/invitation/document123#key=c0be

Every app secretly wants to be local-first

Anselm Eikhoff, creator of the Jazz local-first framework, showed how it works in practice.

He created a simple app for scheduling Instagram posts to demonstrate that modern local-first frameworks work great for prototyping.

Many startups want to add collaboration later, but this feature requires a very specific architecture decision from the beginning. With a local-first sync engine, you already get built-in collaboration.

Using Effect Schema to enable interoperable local-first applications

Jess Martin, the creator of the DXOS local-first framework, talked about an interesting idea: having one database for different applications.

And teir DXOS framework can be this database, providing peer-to-peer sync and identity management out-of-the-box.

You can use the DB schema as a single source of truth for your UI, types, and sync protocol, and you can change only one file to add a new field.

The unreasonable advantage of building local-first

Jack McCloy explained why the time for local-first could be right now.

Currently, users have greater UX expectations. We can contrast this with previous times where, in terms of the market, you didn’t need to be good, your product just needed to work. But now, most markets are already completely crowded, so you need a product that is better, not one that just works.

Figma, Superhuman, and Notion found their way into an occupied market by having better UX. And local-first can bring two essential parts of good UX: performance and collaboration.

We may need even better collaboration support in the future because people and AI agents will work with us on documents.

But writing local-first is hard today, so we need better frameworks, a “Ruby on Rails” for local-first, if you will.

Start with offline—an amazing 13-year journey

Philip Lam told us about Goodnotes, the local-first app with 30M monthly users that was started 13 years ago.

They are making a drawing app, and while using CRDT for drawing is simple, it’s more complicated for text, but they are using Automerge.

Here’s why they started building app as local-first:

  • The low cost of scaling.
  • Local usage was the norm at that time.
  • The local-first stack was easier for them.

Local-first also helps them work with German schools because they care about privacy and ask for local servers or fully offline work.

Lessons for the future of programming languages from a decade of local-first

Alexander Stigsen, founder of Realm, has an interesting idea: We should have DB features in our programming languages for data structures.

It would be cool to have transactions, rich queries, indexes for objects in arrays:

class Task {
 index priority
}
transaction {
  // filter is fast because it uses an index
  for (let task of tasks.filter(priority > 0)) {
 task.progress += 1
 }
}

First local-first: the forgotten history of the early indies

Drew McCormack shared how he was creating local-first apps 12 years ago …before this term was even properly coined.

Initially, all apps were local-only, that is, without sync. But after the iPhone, everyone really started to have 2 devices, and so we moved to the cloud.

Yet, he continued building the old way and started using iCloud Sync; apps just write to the same file (while iCloud syncs files between machines).

This system didn’t resolve conflicts well, so he created a new sync engine Ensembles that could use iCloud, Dropbox, or a selection of many other services (with CRDT, vector clock, and good log cleaning).

Now, he’s happy that the term “local-first” exists. And since we have that word, we can have a conference and talk about it.

Your web app but good

Aaron Boodman from Replicache presented their new local-first DB Zero.

This DB has partial caching on the client and tries to predict what data the user will need. As a result, it will respond instantly to most user requests.

It looks ideal when you don’t need end-to-end encryption, have a lot of data, or rarely use your app, so there is no sense in keeping all data locally.

Local-first and social software

Anton Pronkin from AnyType explained how they are building a local-first peer-to-peer platform where communities can share their knowledge, and even monetize it.

They want to build a “no one in between” social platform, so they use blockchain for data where consensus is needed and local-first where not.

UCAN: Be in control of your auth

Brooklyn Zelenka told about UCAN, an authorization protocol for local-first apps.

Instead of a centralized ACL, with UCAN, each user has a private and public key; they sign a JWT structure where they can delegate some access to another user. That user can then delegate some of their access to the next user.

Each client verifies access in the system using the user’s public keys.

Access control could be even more important since we may soon start to give control to many LLM agents, and we need to be sure about what they can and cannot do.

Little elephants everywhere

James Arthur from ElectricSQL very poetically explained why now is the right time for local-first.

We’ve had many attempts to implement something like local-first before (like CouchDB in 2005).

But today, we have:

  • New browser APIs like WASM and file access allowing us to run SQLite or PostgreSQL in browser (even with dynamic extensions).
  • Many more resources on the client.

Automerge and Version Control for Rich Text

Alex Good from Automerge talked about automatic conflict resolution for rich text and the project’s future plans.

Conflict resolution on a tree structures is difficult, so they work with text like a flow of text symbols and markers, which change format. CRDT works better with list structures.

{ type: 'ul-item' }
first item
{ type: 'ul-item', parent: ['ul-item'] }
nested list item

That above encodes a structure like this:

<ul>
  <li>first item</li>
  <li>
    <ul>
      <li>nested list item</li>
    <ul>
  </li>
</ul>

They’re also are planning to improve memory consumption in the next releases.

Streaming a collaborative filesystem

Yifeng Wang explained how he built a local-first Affine notes/drawing app.

He uses y.js for CRDT and stores data in IndexedDB in the browser and SQLite on mobile.

He has an idea to go further: providing a virtual filesystem to allow many apps (including VS Code, with an extension) to work with documents in local-first systems.

Two myths about building offline-capable SaaS apps

Paulus Esterhazy from the Pitch local-first presentations app told us about 2 myths of offline apps:

  1. Offline support is not a yes/no option, but a spectrum.
  2. Most users don’t need offline support for a very long time. Long latency or unstable connection are much more popular problems for which offline support is needed in your products.

Home-cooked Software and Barefoot Programmers

And Maggie Appleton delivered my favorite talk of the conference about the idea of “home-cooked” applications.

Right now, apps are created by professional developers, require a lot of money, and so they must work for many users. As a result, nobody creates apps for small groups of people. Even so, how would a developer from Silicon Valley understand the needs of a street vendor in Turkey or a doctor in Tunisia?

Yet LLMs allow many people to create apps for their small community or even just for a particular family. These “barefoot developers” from local communities know the community’s needs and do not really need many features or expensive app polishing for the global market.

Local-first is a great fit for the needs of “home-cooked” apps because apps for small communities often work with sensible data.

However, we’re standing at a crossroads, and these home-cooked apps could end up being created in a closed cloud platform owned by a monopolist. If we want better features, we need to create tools for making local-first apps more accessible and democratized.

Local-first creates fresh new challenges for us to deal with in an area full of new ideas and cutting-edge tech. It also unites the community not by a trendy framework but by common principles and values.

To bring things to a close here, I would like to say that enjoyed both the conference and hallway conversations. But let’s keep the conversations going: if you’re interested in joining the community, subscribe to:

Schedule call

Irina Nazarova CEO at Evil Martians

We leveraged Martian open source Logux to build a local-first real-time collaborative diagram composer for Akeero, taking it from idea to MVP in 4 months and helping secure funding. Hire us to build a product that people love and rely on every day.