Blogg
Här finns tekniska artiklar, presentationer och nyheter om arkitektur och systemutveckling. Håll dig uppdaterad, följ oss på LinkedIn
Här finns tekniska artiklar, presentationer och nyheter om arkitektur och systemutveckling. Håll dig uppdaterad, följ oss på LinkedIn
Föreställ dig för ett ögonblick en värld utan spinners – där appar startar omedelbart, samarbetet med kollegor sker utan avbrott, innehållet delas och synkroniseras sömlöst mellan enheter och där nätverkshastigheten aldrig sätter gränser.
Denna vision kan nu förverkligas. Välkommen till local-first-världen.
I den här presentationen utforskar vi hur local-first blir verklighet – från smarta lagringsstrategier och effektiva synkroniseringsmönster till den snabbt växande mängden bibliotek och ramverk som driver utvecklingen framåt. Vi visar också hur dessa principer kan omsättas i praktiken, med Cadec-appen som ett konkret exempel.
Which types of apps are appropriate for local-first?
Productivity applications with real-time collaboration, such as note-taking apps, task managers, and calendars, are prime candidates for a local-first design. These tools need to function seamlessly offline, ensuring users can capture ideas, manage schedules, or update tasks without interruption. For example, Figma and Excalidraw demonstrate how local data storage, combined with Conflict-Free Replicated Data Types (CRDTs), enables real-time collaboration. Users can edit documents simultaneously, even offline, with changes stored locally and synced later—eliminating the “spinners” and delays common in cloud-dependent apps.
Local-first architecture is also well-suited for privacy-sensitive domains like finance and healthcare. Apps can store budgeting sensitive data locally, encrypting it before optionally syncing with the cloud. This ensures users retain full control over their data while still benefiting from cross-device access.
However, local-first is not always the right choice. Applications requiring real-time server validation—such as banking transactions, stock trading, or multiplayer gaming—still rely on centralized systems to ensure atomicity and consistency.
What are good patterns/strategies for handling conflicts when synchronizing local data with the backend?
For local-first applications, Conflict-Free Replicated Data Types (CRDTs) and libraries like PowerSync handle synchronization automatically. It abstracts away the complexity of merging changes across devices, ensuring that: 1) Local changes are always available – No waiting for a server response. 2) Sync happens in the background – Updates propagate once connectivity is restored. 3) Conflicts resolve automatically – Thanks to CRDTs, users don’t have to deal with merge conflicts manually.
How is data migration of the local SQLite handled in regards to App updates?
As mentioned in the presentation, the CADEC App uses Drizzle ORM and PowerSync as key components of the data layer, which help manage schema evolution. However, removing columns is a breaking change. Just like with API evolution, fields should be deprecated first before removal to allow clients time to update.
Will local-first replace the BFF?
Its been proposed that local-first represents the next evolution of fetching and state management, within an app, going from rest to graphql and now to local-first.
If we look at graphql, what a developer is most concerned about is the schema, the shape of the data, typing of queries, mutations and finally caching.
If you setup an api with apollo and then sprinkle in GraphQL-codegen from the guild, one can satisfy all of the above.
Although what about synchronisation and to a lesser extent subscriptions/streaming.
The later is solved nicely with apollo but synchronisation is something you’ll have to solve yourself and many projects do this with varying degrees of genius…
And then, you have the backend layers, gql schema, resolvers caller services or fetching from a db etc etc …
So, if you could work with a strongly defined typed schema, with common querying/mutation hooks, get the whole synchronisation aspect worked out (by experts),
skip having to maintain an api, then really why not?
An essential thing to grasp is that the shape of data, synchronised to your local dbs is the schema. In the power synch example I preseneted in my talk, the synch rules expose Materialised Views of your data which in effect is your schema. The cool thing, is that it gets synched, you skip spinners and you own that data!
I really think that this will take a big dent in the BFF space if not start replacing it, the kids want 60fps!!
Could you use local-first to manage all your data?
With the huge optimisations of sqlite with for instance op-sqlite the gap between fetching data from a db vs from memory is beginning to close. There is obviously still a need for useState within components to handle local state, but for API data I really don’t see why not? If we look at Redux and redux-persist, which uses AsyncStorage under the hood, theres no real reason you couldn’t just replace that with sqlite. Also I stumble across alot of projects, despite using Graph QL still use something like Redux for global state. Personally I’d cut out the middle man and try and simplify the way I fetch and store data. Having said that something like LegendState bridges the gap between local-first and traditional state management, maybe theres a middle ground? See https://supabase.com/blog/local-first-expo-legend-state
Ladda ner presentation