<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/building-localcents-a-local-first-expense-tracker-with-automerge-crdts-98fcddr48" -->

---
title: Building LocalCents: A Local-first Expense Tracker with...
description: A developer walks through building LocalCents, an educational side-project expense tracker using Automerge CRDTs for local-first sync, built as an...
canonical: https://daily.dev/posts/building-localcents-a-local-first-expense-tracker-with-automerge-crdts-98fcddr48
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Building LocalCents: A Local-first Expense Tracker with Automerge CRDTs | daily.dev
og:description: A developer walks through building LocalCents, an educational side-project expense tracker using Automerge CRDTs for local-first sync, built as an...
og:url: https://daily.dev/posts/building-localcents-a-local-first-expense-tracker-with-automerge-crdts-98fcddr48
og:image: https://api.daily.dev/og/posts/98FCDDr48.png
og:image:alt: Building LocalCents: A Local-first Expense Tracker with Automerge CRDTs
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Building LocalCents: A Local-first Expense Tracker with Automerge CRDTs

**[ElixirStatus](https://daily.dev/sources/elixirstatus)** · 7 min read · 8 upvotes · 0 comments

## Summary

A developer walks through building LocalCents, an educational side-project expense tracker using Automerge CRDTs for local-first sync, built as an Elixir/Phoenix app wrapped in Tauri for macOS, with Rustler bridging to Rust. The post covers conflict resolution via Lamport-clock-style operation IDs, a UI for surfacing sync conflicts to users (a notification bell and Conflicts tab), and handling deletion collisions. It closes with reflections on Automerge's access-control gaps (addressed by Ink & Switch's Keyhive project), Tauri's iOS CocoaPods dependency, using a GenServer architecture, Phoenix Storybook experience, and concerns about AI-assisted coding obscuring true understanding of Rust/Automerge internals.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://mikezornek.com/posts/2026/8/local-cents>

## Questions this post answers

### How does Automerge resolve conflicting edits between offline peers?

Automerge picks a deterministic winner using an operation_id, a pairing of a counter and actor id that functions as a Lamport clock. When two peers make conflicting edits offline, this ordering mechanism decides which edit wins once the peers reconnect and exchange changes, with deletions always taking precedence over edits.

_Developers evaluating CRDT libraries can track how sync conflict resolution evolves by following local-first tooling on daily.dev._

### What are the downsides of using Tauri for cross-platform desktop apps with iOS support?

Tauri's iOS support still relies on CocoaPods, a dependency manager that has itself been marked deprecated, making it a notable red flag for teams wanting long-term iOS support. Native-feeling features like system-level context menus require using Tauri's specific tooling rather than generic web APIs, and CSS-based workarounds are used instead in simpler projects.

_Teams weighing Tauri against other cross-platform frameworks can follow ecosystem changes like this on daily.dev before committing._

### What is Keyhive and why does it matter for Automerge-based apps?

Keyhive is a project from Ink & Switch aimed at adding access control capabilities to distributed CRDT tools like Automerge, an area that is otherwise hard to build into a peer-to-peer syncing system. It is considered still fairly bleeding-edge, addressing a real gap for anyone building multi-user local-first applications that need permissions.

_Anyone building permissioned local-first apps can track projects like Keyhive maturing on daily.dev._

---

Tags: [#elixir](https://daily.dev/tags/elixir), [#tauri](https://daily.dev/tags/tauri), [#local-first](https://daily.dev/tags/local-first), [#crdt](https://daily.dev/tags/crdt)

[View this post on daily.dev](https://daily.dev/posts/building-localcents-a-local-first-expense-tracker-with-automerge-crdts-98fcddr48)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Building LocalCents: A Local-first Expense Tracker with Automerge CRDTs","url":"https://daily.dev/posts/building-localcents-a-local-first-expense-tracker-with-automerge-crdts-98fcddr48","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/building-localcents-a-local-first-expense-tracker-with-automerge-crdts-98fcddr48"},"datePublished":"2026-08-31T19:55:32.277Z","dateModified":"2026-08-31T21:22:50.266Z","description":"A developer walks through building LocalCents, an educational side-project expense tracker using Automerge CRDTs for local-first sync, built as an...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/60a2bb372faad4fe3d29ca2e92c9b05e?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/60a2bb372faad4fe3d29ca2e92c9b05e?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"ElixirStatus","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"ElixirStatus","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/22e4640538124187827caf8cc8e39190","url":"https://daily.dev/sources/elixirstatus"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/building-localcents-a-local-first-expense-tracker-with-automerge-crdts-98fcddr48","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":8},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"elixir,tauri,local-first,crdt","timeRequired":"PT7M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"ElixirStatus","item":"https://daily.dev/sources/elixirstatus"},{"@type":"ListItem","position":3,"name":"Building LocalCents: A Local-first Expense Tracker with Automerge CRDTs"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/building-localcents-a-local-first-expense-tracker-with-automerge-crdts-98fcddr48#faq","mainEntity":[{"@type":"Question","name":"How does Automerge resolve conflicting edits between offline peers?","acceptedAnswer":{"@type":"Answer","text":"Automerge picks a deterministic winner using an operation_id, a pairing of a counter and actor id that functions as a Lamport clock. When two peers make conflicting edits offline, this ordering mechanism decides which edit wins once the peers reconnect and exchange changes, with deletions always taking precedence over edits. Developers evaluating CRDT libraries can track how sync conflict resolution evolves by following local-first tooling on daily.dev."}},{"@type":"Question","name":"What are the downsides of using Tauri for cross-platform desktop apps with iOS support?","acceptedAnswer":{"@type":"Answer","text":"Tauri's iOS support still relies on CocoaPods, a dependency manager that has itself been marked deprecated, making it a notable red flag for teams wanting long-term iOS support. Native-feeling features like system-level context menus require using Tauri's specific tooling rather than generic web APIs, and CSS-based workarounds are used instead in simpler projects. Teams weighing Tauri against other cross-platform frameworks can follow ecosystem changes like this on daily.dev before committing."}},{"@type":"Question","name":"What is Keyhive and why does it matter for Automerge-based apps?","acceptedAnswer":{"@type":"Answer","text":"Keyhive is a project from Ink & Switch aimed at adding access control capabilities to distributed CRDT tools like Automerge, an area that is otherwise hard to build into a peer-to-peer syncing system. It is considered still fairly bleeding-edge, addressing a real gap for anyone building multi-user local-first applications that need permissions. Anyone building permissioned local-first apps can track projects like Keyhive maturing on daily.dev."}}]}
```

