Local First – How To Build Software Which Still Works After the Acquihire
#Trends

Local First – How To Build Software Which Still Works After the Acquihire

Python Reporter
6 min read

Alex Good explains how local-first software using Git-like DAG structures and Automerge can create resilient applications that work offline, sync seamlessly, and avoid server dependency fragility.

Alex Good discusses the fragility of modern cloud-dependent apps and shares a roadmap for "local-first" software. By leveraging a Git-like DAG structure and Automerge, he explains how to move from brittle client-server models to resilient systems where data lives on-device. He explores technical implementation, rich-text merging, and how this infrastructure simplifies engineering workflows.

The Problem with Cloud-Dependent Software

Alex Good begins by sharing a personal story about building a simple workout tracking app that worked well until a friend wanted to use it on their laptop. This seemingly small request revealed a fundamental problem: making collaborative software requires building an entire server infrastructure, handling authentication, managing optimistic updates, and creating dependencies on servers that users don't control.

This experience highlighted several issues with traditional collaborative software:

  • Distributed systems complexity: Building server infrastructure requires entirely different expertise than client development
  • User experience degradation: Cloud apps often introduce loading spinners and require network connectivity even for basic operations
  • Loss of creative privacy: Users frequently copy documents to work privately before sharing changes
  • User agency erosion: Users become dependent on servers they don't control, and if those servers disappear (through acquihire, shutdown, or other reasons), their data becomes inaccessible
  • Inefficiency: Powerful local devices become mere display terminals while computation happens on remote servers

The Local-First Alternative

Good introduces the concept of "local-first" software, which prioritizes data living on the user's device as the primary source of truth. This approach offers several key principles:

  • No spinners: Data should be available instantly since it lives on-device
  • Multi-device: Users should be able to access their data across multiple devices seamlessly
  • Network optional: Applications should work offline and sync when connectivity returns
  • Seamless collaboration: Users shouldn't have to manually copy files or manage versions

The Technical Foundation: Git-Like DAG Structures

The core innovation is representing application state as a Git-like Directed Acyclic Graph (DAG) of changes rather than a single source of truth on a server. This structure provides several advantages:

  1. Each device maintains its own commit history
  2. Changes can be merged automatically when possible
  3. Conflicts are resolved locally and can be reviewed later
  4. The same infrastructure supports both real-time and asynchronous collaboration

Good demonstrates this with a simple todo list example. Instead of storing the entire application state as a single JSON file, changes are represented as fine-grained operations on data structures (creating lists, inserting objects, setting values). This granularity allows the system to automatically resolve conflicts that wouldn't actually conflict in the application's logic.

Implementation with Automerge

Good walks through implementing a todo list using Automerge, showing how to:

  1. Set up a repository with network and storage adapters
  2. Create or find documents using URL-based document IDs
  3. Capture changes using docHandle.change() instead of direct state mutation
  4. React to changes automatically without manual UI updates

The key insight is that application logic remains simple - developers just manipulate JavaScript objects, while the infrastructure handles synchronization, conflict resolution, and storage.

Advanced Features and Real-World Applications

The local-first approach enables powerful features that are difficult with traditional architectures:

  • Rich text editing with automatic conflict resolution
  • Drawing applications with change visualization
  • Review workflows for complex changes
  • Version control for arbitrary data types

Good demonstrates these capabilities with examples like editing RFC documents and collaborative drawing tools, showing how the same infrastructure that enables synchronization also provides change tracking and review capabilities.

Challenges and Future Directions

Despite the benefits, several challenges remain:

  • Authentication and authorization: Current solutions require custom server logic
  • Indexing and partial synchronization: Users may not want all data on all devices
  • Schema enforcement and evolution: Applications need to maintain invariants across different versions
  • Performance optimization: Change history can become large and needs compression

Good mentions ongoing research into cryptographic key-based authentication and schema management to address these issues.

The AI Connection

An interesting insight is how local-first infrastructure complements AI development. Since LLMs are powerful but unreliable, applications need robust change management to review and approve AI-generated modifications. The same infrastructure that enables local-first collaboration also provides the version control needed for safe AI integration.

Conclusion

The local-first approach represents a fundamental shift in how we think about collaborative software. Rather than building applications as thin clients for remote servers, we can create resilient systems where data lives on the user's device, collaboration happens seamlessly, and users maintain control over their information. This not only improves user experience and privacy but also reduces development complexity by eliminating the need for custom server infrastructure.

The vision is compelling: applications that continue working even when servers disappear, that respect user privacy by keeping data local, and that provide the same seamless collaboration we expect from cloud services without the fragility and dependency on centralized infrastructure.

Featured image

Local First – How To Build Software Which Still Works After the Acquihire - InfoQ

Questions and Answers

Participant 1: How do you handle server-side functionality that can't be replicated locally, like e-commerce checkout or third-party integrations?

Alex Good: For operations that require server-side execution (like sending emails or processing payments), you need specialized servers that control access to those specific side-effecting operations. The goal is to make these servers smaller and more constrained rather than having them manage all application state.

Participant 2: How do you handle relationships between data elements when the commit history might break external constraints?

Alex Good: This is part of the schema management challenge. Current approaches often use optimistic strategies where invalid references are ignored. The long-term solution involves custom operation types that encode invariants and ensure dependencies exist in the commit DAG.

Participant 3: How do you handle software versioning and distribution in a local-first system?

Alex Good: Software distribution can still use central entities, but the key is ensuring the application continues working without the server. For fully decentralized publishing, approaches like certificate transparency or public data infrastructure could be used, but this is an orthogonal problem to local-first architecture.

Participant 4: How do you handle devices with different performance capabilities?

Alex Good: The concept of "shallow clones" allows low-power devices to only sync the latest state rather than full history. They can request changes from more powerful peers who handle the commit DAG integration.

Participant 5: How do you handle the performance impact of storing full change history?

Alex Good: Real systems use compression techniques like run-length encoding to minimize metadata overhead. Instead of storing individual commits for each keystroke, they store ranges and recalculate hashes when needed.

This approach to software architecture offers a compelling alternative to the current cloud-dependent model, promising more resilient, private, and user-controlled applications while potentially simplifying development by eliminating complex server infrastructure.

Comments

Loading comments...