Diving in to local-first software
I’ve been spending quite a bit of time exploring and learning about local-first software. It’s a newer word for an older idea thats been gaining traction, and I think we’re going to see this momentum continue and more web applications built using these concepts.
There’s a lot of excellent resources and discussion on this topic (I’ll link out to these), but I’d like to make a case for what it means for designers and share why I find it so exciting. I’ll run through what local-first software is, how it leads to higher quality software, and the challenges and approaches for applying this practically.
A note before jumping in… a lot of these concepts aren’t new ideas. This is my effort to articulate some complex concepts with a design lens for my own understanding, and share some of my experience trying to apply these concepts! For another perspective on what this is and how to make it accessible, I’d recommend this excellent talk from Maggie Appleton.
What is local-first?
The term was introduced in 2019 by the research lab Ink & Switch. In Local-first software: you own your data, in spite of the cloud, they define seven ideals for what what local first software should embody. These ideas have been around for along time and were probably called “offline-first” previously. The term has been a bit diluted from the original concepts proposed by Ink & Switch, and many people now use it for software that doesn’t hit all seven ideals. The common thread relates to how data is stored in web applications.
With local-first, the first place data is stored is on a user’s computer. These apps often include a sync engine so data is can be shared across devices, backed up, and edited collaboratively. This makes applications fast and have a much more native feel, and it also is a great architecture for “multiplayer” experiences. Two success stories that are frequently mentioned in this space are Linear and Figma.
Benefits of local-first
This architecture ends up having some big wins for both the end user experience and the developer experience. Both of these are valuable for designers to be aware of as they impact the overall quality of web applications. I’ll walk through specific advantages, but at a high level a lot of common issues with web applications are solved out of the box. You get a lot of quality for free, designers can focus on the UX of core workflows, and developers can build and iterate on these features more quickly. Tighter and more focused feedback cycles lead to better software!
Okay, now for the specifics…
Performance
From a user’s perspective, these applications feel fast. In most cases the UI responds instantly. The user doesn’t have to look at loading states, spinners, and skeleton UIs. Designers don’t have to waste time thinking through these placeholder states, and developers don’t have to waste time building them. It also feels much closer to a native experience you’d get with a desktop or mobile app. As web applications are increasingly deployed as native experiences with frameworks like Expo, React Native, and Electron, this is even more important.
- Dig a bit deeper
- Imagine adding a todo item within a simple todo app. With a traditional web app, after you write the todo and click “add”, the client does a round trip with the database where it writes the todo to your to do list, waits for conformation, then shows it in your todo list. With a fast internet connection the delay is probably less than 200ms—quick but noticable. With a slower internet connection there’s an even more perceptable lag between button click and item in the list.
- Optimistic UI updates work around this by immediately showing the item in your todo list and confirming it when when the round trip is complete. This works relatively well, but its added complexity for implementation and introduces edge-case states that need to be designed and thought through. If theres an issue with the database write, the user will see the todo item show up then mysteriously disappear from their list. Thats confusing!
- Two common workarounds are loading states and optimistic UI updates. Loading states can take the form of skeleton UIs, spinners, and progress bars, and these often degrade the user experience as they slow you down and add visual noise. This also creates a lot more UI that has to be thought through and built.
Work offline
Often users have access to fast and reliable internet, but its not a given. If the tab has been opened once, the user can use the entire app regardless of their internet connection. This means a great user experience even on the spotty cafe wifi, on a flight, while traveling, or with no service during a road trip. When internet comes back all the work they did is synced and saved. And again, designers don’t have to worry about edge cases and messaging.
Sync between tabs and devices
I often intentionally or unintentionally open up the same app in multiple tabs, or make a change on my phone while I’m working on something on my computer. Local-first apps handle this gracefully, with changes syncing nearly instantly. This helps users stay in a flow state and seamlessly move between devices. There’s a growing movement to store more than application data in the distributed state, so things like a specific filter configuration or.
Easy multiplayer and collaboration
Being able to collaborate in real time is a huge value add for Figma. It’s a productivity boost to be able to work on the same document in real time, and its also a lot of fun to have the sense of presence you get when seeing another another cursor or avatar in a document. Designers don’t have to worry about creating UI’s for managing and sharing versions of a document, and we don’t need to worry about creating workflows and UIs for merging documents and managing conflicts. These get complicated fast and it’s so much nicer to just work off a single source of truth.
Undo and redo
This is challenging to build but extremely high value feature. This is such a well established pattern with computing because it saves us when we make mistakes, encourages exploration and experimentation, allows us to back track at zero cost, and gives a general sense of safety when using an app. Many local-first sync engines use CRDT’s to manage distributed state and collaboration, which lend themselves really nicely to implementing undo stacks. There’s still overhead to building this functionality, but its more accessible than standard web app architectures.
Privacy and data ownership
Owning your own data isn’t necessarily a part of the day-to-day ux of an application, but its worth calling out as a win. Ink & Switch use the term “the long now” to describe longevity in software. When you aren’t reliant on a company to store and manage your data, you can keep using the software even if the company goes under. Obsidian is a real-world example of this in practice, where the underlying files you use are just a folder of markdown files.
Authentication and onboarding
Related to data ownership, there’s an interesting opportunity for low-friction onboarding with local-first software. There’s an emerging pattern where a user doesn’t have to sign up to start using an app. You launch the app, start using it, and with zero friction can experience the value proposition. The data is stored locally, and you could even close the tab and as long as you come back on the same browser or electron app, your can pick up where you left off. If you want to save your data, you can sign up for an account which is essentially a sync service. Again Obsidian is a good example for this. You don’t ever need to sign up for an account and can just point the app towards a folder on your computer. You can sync using iCloud, dropbox, or pay them for their sync service.
Applying these concepts
There’s a lot of value with this approach, so why aren’t more apps built like this?
The reality is there is a big technical cost to setting up the initial sync engine. Both Figma and Linear spent years building the sync infrastructure. (Check out How Figma’s Multiplayer Technology Works and Linear’s Realtime Sync System if you wan’t to go deeper on those.) Building sync from scratch is not feasible to a lot of teams, and it feels especially out of reach to a designer-builder like me.
The good news is that there’s a lot of very smart people working on tools to make this more accessible, and there’s some new and exciting things on the horizon. Some of them are do everything solutions and others are more flexible. I’ll call out some specifically, but if you want a full list of build tools, articles, and videos, and builders in the space, check out localfirstweb.dev.
If you’re a designer who’s not doing any building but want to explore this approach, these are some good resources to share with the rest of your product team to explore feasibility. If you’re a designer who is building, I’ll share my experience actually putting some of this into practice. Once you get past the initial setup, you can focus your energy on the front-end and have to worry a lot less about the database. Tread carefully though! This is an emerging space with fewer resources and more dragons. Things feel like magic when they’re working, but when you stray from the path or run into problems it can get frustrating quickly.
Rocicorp: Replicache → Zero
Rocicorp is one of the established tool makers in the space. Their product Replicache is a powerful and flexible sync engine that works with different back ends. There’s a fair amount of set-up required and it didn’t feel super accessible to me. They had a more plug and play option called Reflect, but thats been shut down as they focus on a new product: Zero. It’s in private alpha now but I’m really excited to give it a try — they’re promoting this as a much more comprehensive and accessible solution to sync.
Powersync
This is what i’ve been using to build local-first apps and its been a joy to use. You can bring your own postgres database and it handles all the syncing. After trying out several options, I picked it because it integrates nicely with Supabase (and Supabase auth) and they have some relatively mature docs and examples. One of the things i’ve enjoyed most is that most of the database configuration happens in Supabase, and there’s lots of resources and tutorials in that space. I’ve also been building with NextJS due to the amount of resources available, and I put together a starter to use ShadCN UI and have it available as an open source template. There are free and self-hosted options, but you can also pay to use their cloud system.
ElectricSQL
This was a close second pick for me as it also integrates nicely with Supabase. They also went through a big re-write after I did my research and I’d like to give it another shot. The fact that so many of these services are going through big full-system rewrites is a testament to how hard this problem is. Their website is also great and does a particularly good job explaining how sync works. I believe this is self-hosted only at the moment, and they have an upcoming hosted cloud option that is in private alpha as of November 2024.
Liveblocks
I also have experience using liveblocks and used it to build real-time multiplayer threejs apps I was exploring. Its marketed more as a real-time collaboration and conflict resolution service but they do mention local-first storage in their APIs. Its high polish but extremely expensive.
Expo / Prisma / React Native
Prisma has recently added local-storage support for Expo and React Native.
Other tools
There’s so many options! A few other of note are TinyBase, Dexie / Dexie Cloud, Automerge, Jazz, Instant, and LiveStore. Honestly a lot of this will probably become outdated soon given the current pace within this space.
Additional resources
localfirstweb.dev A comprehensive list of build tools, articles, and videos, and builders in the space.
Home-cooked Software and Barefoot Programmers: Maggie Appleton (Local-First Conf) One of my favorite talks from the first Local First conference. I particularly appreciate her perspective as a “Designer and mediocre dev” making the case that local-first and LLM’s are going to democratize software creation. I’d also recommend this talk and really any of the talks from that conference.
localfirst.fm A very thoughtful and well produced podcast with a lot of the key builders in the space. A lot of the discussion is more technical than the work I’m doing, but it’s helpful to hear about how people are approaching different sync problems. As a music nerd lamenting how impersonal music streaming is, I’m also chomping at the bit to try Overtone.
Syntax FM:
Additional Resources: