This is very much "draw the rest of the owl".
Creating a CRDT model for your data that matches intuitive user expectations and obeys consistent business logic is... not for the faint of heart.
Also remember it turns your data model into a bunch of messages that then need to be constantly reconstructed into the actual current state of data. It's a gigantic enormous headache.
Technically an algorithm that lets the last writer win is a CRDT because there is no conflict.
Making a true system that automatically merges data while respecting user intent and expectations can be an extremely hard problem for anything complex like text.
Another problem is that in some situations using a CRDT to make the conflict disappear isn’t even the right approach. If two users schedule a meeting for the same open meeting room, you can’t avoid issues with an algorithm. You need to let them know about the conflict so they can resolve the issue.
Yes. It’s called a LWW register in the literature. Usually a MV (multi value) register is more useful. When there is a conflict, MV registers store all conflicting values and make any subsequent reader figure out what to do.
But for my money, usually what you want is something operation based. Like, if we both append to a transaction list, the list should end up with both items. Operation based CRDTs can handle any semantics you choose - so you can mix and match different merging approaches based on the application. And the storage for LWW and MV is the same, so you can start simple and grow your app as needed.
IMO the reason local first software is still not popular is the same reason encrypted messaging apps took awhile. There’s a lag from good CS research enabling a class of applications and good implementations being available with good UX. Most CRDT implementations are still pretty new. Automerge has been really slow until quite recently. Most libraries don’t support ephemeral data or binary blobs well. And there aren’t a lot of well defined patterns around user login and authentication. Local first apps today have a lot of work ahead of them to just exist at all. Give it some time.
"If it’s older → ignore" -- yea, I guess that's a solution but I would really have to look for the problem.
I've gone down this road and considered github (or similar) as the backing database. In the end, I just don't have an answer that isn't specific to nearly every field that might be entered. A notes field might be appended. First in might be important, or last in (if it can be trusted as correct). Usually it's something like, "which of these two did you meant to capture?"
Balance = 100 A: balance = 120 B: balance = 80
Clearly, these are transactions, and it doesn't matter in which order they're applied, but it does matter that they're both executed. End balance should be 100, not 80 or 120.
This solution doesn't nearly move us toward making local-first apps more popular, which was nominally the theme.
Or does it just double book the room? Or is there a global lock on any transaction affecting a meeting room, so only one goes through? (Feels like it doesn’t scale)
They just can't send the acknowledgement of "succesfully booked" yet.
Why wouldn't it scale? How many meetings are booked per second in your organization???
That's not a real problem - at least not in the "book a corporate meeting room" space.
A traditional database funnels all your data changes down to one leader node which then accepts or rejects them, and (if A+C in the case of single node failure is desired) makes sure the data is replicated to follower nodes before accepting.
A distributed database is similar but different pieces of data can be on different leaders and different follower sets.
This comment was rate-limited.
Simple: It’s server based. These problems are trivial when the server is coordinating responses and the clients can only reserve a room if the server confirms it.
This is the problem that gets hand waved away with local first software that has multi user components: It doesn’t take long before two users do something locally that conflicts. Then what do you do? You have to either force a conflict resolution and get the users to resolve it, or you start doing things like discarding one of the changes so the other wins.
Hell, it's so feasible, it can even done manually IRL by some person (like discussions where a person holds the "talking stick" and only there are allowed to speak until they pass it to another person - that's a lock).
- prefer seniority - prefer pay scale - prefer alphabetical - roll dice
That’s how a business would probably do it since the first two alone align with how the business already values their Human Resources, which would translate to “the objects that the Human Resources compete for”
In a well designed system, the intern will be delegated with “room booking authority” on behalf of their most senior manager on the calendar invite.
Using something like this, that would be in the CRDT resolution algorithm.
https://w3c-ccg.github.io/zcap-spec/
Company culture will recognize it is an HR problem.
Your comment shows some ignorance and a complete misunderstanding of the problem domain.
The whole point of CRDTs is that the set o operations supported is designed to ensure that conflict handling is consistent and deterministic across nodes,and the state of all nodes involved automatically converge to the same state.
Last-write-wins strategies offer no such guarantees. Your state diverges uncontrollably and your system will become inconsistent at the first write.
> Making a true system that automatically merges data while respecting user intent and expectations can be an extremely hard problem for anything complex like text.
Again, this shows a complete misunderstanding of the problem domain. CRDTs ensure state converges across nodes, but they absolutely do not reflect "user intent". They just handle merges consistently. User intent is reflected by users applying their changes, which the system then propagates consistently across nodes.
The whole point of CRDTs is state convergence and consistency.
This article is a perfect example: it says syncing is a challenge for local-first apps, logical clocks and CRDTs are the solution, and then just ends. It ignores the elephant in the room: CRDTs get you consistency, but consistency isn’t enough.
Take a local-first text editor, for example: a CRDT ensures all nodes eventually converge on the same text, but doesn’t guarantee the meaning or structure is preserved. Maybe the text was valid English, or JSON, or alphabetized, but after the merge, it may not be.
My suspicion, and I might be going out on a limb here, is that articles don’t talk about this because there is no good solution to merging for offline or local-first apps. My reasoning is that if there was a good solution, git would adopt it. The fact that git stills makes me resolve merge conflicts manually makes me think no one has found a better way.
Git is a good example though as we can definitely write merge algorithms that get good results in many more cases than git's default but with something like code it's preferable to let the human user decide what is the correct merge solution except trivial cases. Still, a language aware merge algorithm could do a lot better than git in both automatically merging more cases and refusing to merge nonsensical combinations of commits that don't touch the same lines.
> Your comment shows some ignorance and a complete misunderstanding of the problem domain.
oof, this is a very strong position to take, and one would assume you have a very convincing follow up to back it up.
And unfortunately I don't think you do. CRDTs can definitely be implemented as a last-write implementaiton. This should be obvious for state-based crdts. The problem is that it's a horrible UX because somebody could type a response to something that's out of date, and then just see it dissapear as they get the most recent message.
Resolving "user intent" by choosing how to structure the problem domain (e.g. storing ids for lines, and having custom merging solutions) so that it reflects what the user is trying to do is the main challenge.
I am quite frankly baffled at how arrongant your tone is given how far off the mark you seem to be. Genuinely makes me think that I am missing something given your confidence, but I don't see what point you're making tbh.
Imagine how better your comment would be if you ommited the above line, which adds nothing to the correction you try to make, but comes off as stand-offish.
"Braid’s goal is to extend HTTP from a state transfer protocol to a state sync protocol, in order to do away with custom sync protocols and make state across the web more interoperable.
Braid puts the power of operational transforms and CRDTs on the web, improving network performance and enabling natively p2p, collaboratively-editable, local-first web applications." [4]
[1] A Synchronous Web of State:
[2] Braid: Synchronization for HTTP (88 comments):
https://news.ycombinator.com/item?id=40480016
[3] Most RESTful APIs aren't really RESTful (564 comments):
https://news.ycombinator.com/item?id=44507076
[4] Braid HTTP:
After doing this a few times, your stakeholders are probably fed up with the crawling pace of development, and the whole local-first app is scrapped again and replaced by a more traditional app. Maybe the architect is fired.
There is at least one alternative "CRDT-free" approach for the less brave among us: https://mattweidner.com/2025/05/21/text-without-crdts.html
Seems like a terrible trade to me. Just use a crdt. They’re good.
The author has made a CRDT. He denies that his algorithm constitutes a CRDT. It's a straightforward merge, not a "fancy algorithm".
What specific aspect of a CRDT does this solution not satisfy? The C? The R? The D? The T?
Still, every algorithm that's actually labeled a CRDT shares a magical property: if my replica has some changes, and your replica has some changes, our replicas can share their changes with each other and each converge closer to the final state of the document, even if other people have been editing at the same time, and different subsets of their changes have been shared with you or I. That is, you can apply peoples' changes in any order and still get the same result. I don't think it's useful to call anything without that property a CRDT.
CRDTs are a complicated way to solve a problem that most services don't really have, which is when you want to sync data but don't want to have any one client be the ultimate source of truth.
And for the younger devs: please consider if you need these kinds of sync systems at all (distributed & offline modes), sometimes a simple store-forward of events and/or cache is all you need. If you have some leverage, try to advocate that your application has a hard requirement on an internet connection as often it is cheaper to install fibre redundancies than dealing with the side effects of corrupted or lost data. Might save you from early grey hairs.
ps: the above is written with business/LoB applications in mind, with some offline mobile/desktop apps in the mix, not things like control systems for factories or real time medical equipment.
I don't this is true at all. A CRDT is not your data model. It is the data structure you use to track and update state. Your data model is a realization of the CRDT at a specific point in time. This means a CRDT instance is owned by a repository/service dedicated to syncing your state, and whenever you want to access anything you query that repository/service to output your data model.
Sometimes problems are hard. Sometimes you create your own problems.
CRDT's generally require you to track a lot more stuff in your snapshot model than you would otherwise, in order to create messages that contain enough information to be applied and resolved.
E.g. what was previously an ordered list of items without ID's may now need to become a chain of items each with their own ID, so you can record an insert between two other items rather then just update the list object directly.
So yes, the CRDT is effectively your data model.
Just ignore the conflicts. The last change wins.
No, really. In practice for most cases the conflicts are either trivial, or impossible. Trivial conflicts like two people modifying the same note are trivial for users, once you have a simple audit log.
And impossible conflicts are impossible to solve automatically anyway and require business processes around them. Example: two people starting to work on the same task in an offline-enabled task tracker.
I agree that this means humans intervening.. It sounds like there was a comms breakdown. But rather than doing a first-in-best-dressed, it sounds like accurately recording that both users are in fact working on the same thing is the best option since it surfaces that intervention is required (or maybe its intentional, tools insisting that only one person can work on an item at once annoys me). Sounds much better than quietly blowing away one of the user's changes.
In principle, local-first to me means each instance (and the actions each user carries out on their instance) is sacrosanct. Server's job is to collate it, not decide what the Truth is (by first-in-best-dressed or otherwise).
These kinds of conflicts simply can not be solved by CRDTs or any other automated process. The application has to be designed around that.
> In principle, local-first to me means each instance (and the actions each user carries out on their instance) is sacrosanct. Server's job is to collate it, not decide what the Truth is (by first-in-best-dressed or otherwise).
This makes sense only for some applications, though.
And we have not yet started talking about permissions, access control, and other nice fun things.
I probably should have been explicit in that I'm not arguing in favor of CRDTs, just that the adverse doesn't need to be "send it and accept the collateral".
Draw The Rest Of The Owl energy here, but at least its a nice northern star.
https://github.com/evelant/synchrotron
Idea is to sync business logic calls instead of state. Let business logic resolve all conflicts client side. Logical clocks give consistent ordering. RLS gives permissions and access control. No dedicated conflict resolution logic necessary but still guarantees semantic consistency and maximally preserves user intentions. That’s the idea at least, requires more thought and hacking.
It's like Ethernet conflict resolution: just access the shared medium and detect collisions in real time.
Of course, you know the answer: if you're offline, you're not online. Bob gets to type whatever Bob wants, and until you go online, you don't get to overtype anything.
Both sides type offline and only sync later. Neither would like their change to just be discarded.
https://news.ycombinator.com/item?id=45341335 "We have a local-first app. Our approach? Just ignore the conflicts. The last change wins."
if you can see the edits being made in real time, keystroke by keystroke, that pretty much solves that problem.
As for offline editing, either don't support it (then you're not local-anything obviously) or you can have some lame workflow like "the document was changed by another user ..."
If you have a CRM-like application with a list of users? Not so much.
But since the entire world economy has turned to purely optimizing for control and profit, there's just no good reason to not screw people over as much and as often as possible, what'll they do ? Switch to someone who won't ? And who would that be ?
I worked on a somewhat well-known (at the time) product that used on-site hosting.
One of our biggest customer complaints was that we didn’t have a cloud hosted option. Many companies didn’t want to self-host. They’d happily pay a premium to not have to host it.
I think HN underestimates the demand for cloud hosted solutions. Companies don’t want to deal with self-hosted if they can pay someone else a monthly fee to do it.
Otherwise it seems like I'm just spending time and effort achieving the exact same result.
There are also products that still have licensing costs even when you self host.
I've worked at a large company that self-hosted Atlassian products that were a big part of a full-time team's job.
I've worked at a large company that built virtually all their internal tooling in house.
I've worked at a large company that used cloud-based vendors.
They all had tradeoffs.
One of those companies even forced a migration from cloud based CI to internal CI for cost reasons then stopped us halfway through because they couldn't scale up our hosted CI to keep up fast enough.
I could argue your answer is just as short-term thinking when your critical tools end up costing you more hardware, data center, and salary opex than you planned for (which I have seen).
Granted, this is a business that needs on-premise infrastructure anyway because we have inhouse production. So we have a domain controller that can be used for everything auth. We use a combination of that and Entra (shitty name).
I wouldn't want to host Jira because I don't like to work with it. Our wiki is self-hosted as well.
Sadly, we also buy into MS infrastructure and use SharePoint and co. It is soo incredibly slow to work with...
While you can be cloud only, it isn't an environment I would like to work in. Local alternatives are almost maintenance free these days and the costs are so much less for a faster service.
For example: how much time do I want us to spend looking after a task/ticketing system? About zero. How much time do I want my org to invest in DR planning for our self-hosted wiki? About zero.
So unless there's a convincing difference (cost, features, etc), cloud-hosted SaaS would be my choice there.
The answers also probably change a lot based on how the company operates. Would I have been comfortable with a self-hosted wiki when I worked at Facebook and we had a pretty damn good team providing DBs as a service? Yes. Would I have wanted to do the same when I was the sole infra person in my group at another job? No.
Also, an experienced admin can setup a repository server in a day. This is probably even less time investment than getting offers for solutions. In my opinion the maintenance amount isn't less with SaaS at all as most maintenance work is integrating data.
We do have a self-hosted wiki. We don't even need to think about it if we want to integrate document search or analysis. We own our data completely here and I would argue that data is quite an important chunk of wealth for a company. Some SaaS companies know that as well and they basically take your data hostage. And as a plus, as many things are on a local network, any access to that data is pretty much instant.
To save time on infrastructure decision overall is a mistake in my opinion. You wouldn't do that for your ERP or CRM solutions either.
GPU-heavy tasks were also heavily in favor of buying hardware and self-hosting at the time I was making purchasing decisions at my job.
Not everything falls in that bucket and the examples in my comment don't (GitHub isn't just runners).
Edit: I'll also add a question: what part of "unless there's a very big financial cost difference that more than offsets my time and hardware investment" did you think would not cover "have you checked the cost of GitHub runners?"
In general, I do prefer fixed costs, so self-hosting resource-intensive things makes sense.
Obviously if your constraints are different, do what works for you.
That argument flies in the face of basic economics.
The problem is that the people don't seem to care about being screwed. If they did, it would very profitable to provide the non-screwing, and lots of people would.
The optimist in me believes this is a just a problem of education, understanding, and risk-assessment (ie, the screwing is hidden to them). But even if we grant this, that turns out be a very hard problem to solve.
The first think any economist will tell you about the foundational rationale of basic economics is it's inability to explain the discrepancy between behavior as predicted by basic economics and behavior as carried out by human beings in the actual real world.
The hard truth that I, a human, do not behave rationally and in my own best interest at all time, or at least in those situations in which the risk or benefit to myself is the greatest, is a hard one to swallow, and many people are innately unable to even consider swallowing that, and as a result, to maintain their own illusion of rationality, they must take the stance that humans are as a rule, rational and therefore will act rationally and in their own best interest, if nothing else, as a preemptive defense against the question "if everyone around you is irrational, then what's the chance that you're the only rational one?"
The issue is that it's not as simple as just "switching" and giving another company your money. How would you migrate your 5-10 years of Confluence pages and Jira tickets if you wanted to switch from Atlassian? You're going to put all of your members through the hassle of switching a booking service/payment process? You know you're being screwed, but the cost to switch is often more than the increased cost. The modern economy is balancing cost increases to your customers with the cost to switch to a competitor.
The problem with people's basic understanding of free markets is that it is heavily simplified. We are looking at it from the perspective of 'what if human nature wasn't ever a problem, everyone was always perfectly rational, and everyone had all of the information they needed to make a rational decision'. Those criteria do not and have never existed, which is why the free market fails sometimes at doing some basic things.
Don't get me wrong, it is a great idea and it solves all sorts of problems and we should keep using it -- but don't come to the conclusion that because it all works out in the theory part, then if something in the real world is a certain way then we have to accept that it is efficient and inevitable.
It merely relies on the love of money of real people in our current economy, and the premise that there is enough information flow that, if people cared, they would find and pay for products that don't screw their privacy, control, etc. I think both those premises are undeniably true.
That's a terrible premise. Why are you assuming that this flow exists and that billions of people are failing individually rather than the simpler one this flow not existing?
We can always say the case hasn't been made well enough, and maybe it hasn't it, but at what point do you just start believing people?
If I misunderstand you please correct me.
If that is what you contend, then you have no addressed whether or not the market allows them to do otherwise. You take for granted that the market is free and that people are willingly choosing this outcome with perfect knowledge and without any incentives or forces which would compel them to act despite not wanting to be screwed. For instance, if you do not have bargaining power with a company over your contract, you have no choice but to accept it. Can you enter into negotiations before agreeing to a EULA?
There are forces that are not free market forces which constrain actions, there is human tendency to prioritize immediate needs over long term benefits, etc which all play a role.
The fact that:
1. The market exists 2. We have a conception of how the market should work in an ideal 3. People act in a certain way
do not all combine to make it true that 'people prefer it this way'.
That's the point I am making in counter to your assertion.
You're bringing up all these theoretical counterpoints that either obviously don't apply, or only apply very partially. There are many local only, FOSS options available for every type of software, right now, many free, for people that care about privacy and control in their computing. They generally have tiny market share. If they were made even more convenient, I don't believe the impact would be substantial. By that I mean stuff like brand recognition, what friends are using, and so on would still be more important decision factors than privacy/control features.
This is a people problem, not a "free market not behaving like its theoretical model" problem. Either people don't fully understand the meaning and importance of their privacy, or their revealed preference of not caring that much is just... sadly... true.
Sorry if I was talking past you instead of with you, but I have to say that I don't think it is fair to call my responses 'theoretical counterpoints'. What I am doing is pointing out that on the face of your claim, you are engaging in what could reasonably be called 'begging the question'. That is, assuming the conclusion in your own argument without actually showing that that conclusion has a logical basis. Saying 'the current situation exists, and because people have mechanisms by which they can affect that situation that means they are in complete control of the situation' is not logically valid unless you can account for those things which they do not have mechanisms to control being irrelevant to the outcome.
Maybe it is the latter, who knows. But what I do know is that the non-screwing options exist, but are often less popular and more expensive (either in price, time, or effort).
And this annoys me to no end. Because _I_ don't want to be screwed. But whether I get screwed or not increasingly depends on how much those around me are willing to get screwed or not.
You yourself admit that while you don't want to be screwed you only have the option of not being screwed if those around you also choose not being screwed yet somehow you conclusion that others are different and must be OK with being screwed. Presumably you also often choose being screwed over being socially ostracized? Do you really make sure that all those around you have options to still interact without without being screwed?
Yes people often technically have options of not getting screwed but those options almost exist in a different world and in order to choose them you have to abandon the one you are living in now. That people cannot afford to do that does not mean that they are OK with being screwed.
"Yes people often technically have options of not getting screwed but those options almost exist in a different world and in order to choose them you have to abandon the one you are living in now."
But the question that remains is this: If the true situation is people who'd desperately like not to be screwed, and would pay the same or more for this privilege, but are made helpless by corporate propaganda and market dominance, why do we not see new players rushing in to fill this need? They could take massive amounts of market share.
There are only two explanations I can see:
1. Monopoly forces or similar at work.
2. This is not the actual situation.
Regarding 1, you can make the argument for a network effect/coldstart problem. That seems possible to me as an alternative explanation, and as a way out. Still, in my personal experience, 90% of people just don't care that much, and so are vulnerable to essentially being "bribed" by short-term corporate incentives. The free/privacy-respecting alternatives would have to match this force, and also match the marketing.
No, I only choose being screwed over being homeless, or jobless.
Which didn't use to be a particularly likely scenario but the tides are turning.
I don't care about being socially ostracised for refusing to ever use WhatsApp for example.
We teach children not to cave to peer pressure as if it was a choice they could make, and now you're claiming that caving to peer pressure is not something people choose.
I invite you to figure out how to algorithmically figure this out in a general case without needing Git Merge levels of complexity for data structures far more complicated than lines of code. Peer to peer device merging of arbitrary files for n > 2 conflicts.
The answer - the algorithmically simple and correct answer - is to have a central hoster and the devices operate as clients. And if you have a central hoster, you now gave yourself a job as sysadmin with requisite backup/failover/restore with data management responsibility handling the decade+ case. Or I could hire a central cloud company to manage my tiny slice of sysadmin needs and _not_ have a part time job at home just dealing with file management and multifile merges.
All models that are "I have a laptop and a backup hard disk" are _broken_.
FOSS
Citation needed.
My current thinking is that the only way we get substantial local-first software is if it's built by a passionate open-source community.
Most people have a Dropbox, Apple Storage, Google Storage or similar.
A lot of people used to happily pay for desktop software.
It is sort of a combo of those 2 things economically.
Dropbox could sweep up here by being the provider of choice for offline apps. Defining the open protocol and supporting it. adding notifications and some compute.
You then use Dropbox free for 1, 5, 10 offline apps (some may need free some paid) and soon you'll need to upgrade Storage like any iPhone user!
More or less no one used to "happily" pay. Absent pirating software, they did pay often hundreds of dollars for all sort of software sight unseen (though shareware did provide try before you bought) which often came with minimal updates/upgrades unless they paid for such.
But expectations have largely changed.
It’s not immune to file conflicts across your devices though.
Adobe is keen to emphasize that their products are cloud based
That would let you access your data forever, albeit you might still need to write your own scripts to port it to another app.
What point are you trying to make?
The really crazy thing is that everyone just forgot a couple of years ago "Dubai chocolate" meant something a lot more gross.
It's called damage control and yes it's crazy that we blindly allow this kind of society-wide manipulation.
And the price they give me from clicking the ad is a limited-time discount so then I'm turned off from ever coming back later and paying the full price i.e. the sucker's price.
Surely this isn't the optimal business model for many of the products that have adopted it.
I see product X is $10/month. I subscribe. I'm not sure where the deception is there? The alternative is likely either the cost of the product is exorbitantly high like $500 for lifetime. Or the developer makes it more affordable but sales peter out and they end up having to go out of business and can't afford to maintain the product after a couple of years. Likely both. And hackernews will complain either way.
The only sustainable model I've seen is lifetime licenses but updates for a single year.
Look at single player video games, cannot get more ideal for local-first. Still you need a launcher and internet connection.
We drove everything online for logistics and financial reasons. Not because the tech requires online connections for everything. it isn't changing because people don't see always-online as a big enough deterrent to change their habits.
There are currently tens of thousands of games that are unplayable due to requiring pinging to a network/patch server which long ago was deprecated.
Forsaking patch requirements, just as many games are no longer playable due to incompatibility/abandoned OS, codebase, gamebreaking bugs.
In both of these scenarios, my "lifetime license" is no longer usable through no action of my own, and breaks the lifetime license agreement. I shouldn't need to be into IT to understand how to keep a game I bought 5 years ago playable.
The solution to this "problem" for user, as offered by the corporate investment firms in control, is to offer rolling subscriptions that "keep your license alive", for some reason. Rather than properly charge for a service at time of purchase.
TLDR: Why move the goal posts further in favor of tech/IT/Videogame Investment firms?
Two people meet in an HN thread, and they both dislike the status quo in a particular way (e.g. that copyright is awful, DRMed games suck, whatever). They both want to fight back against the thing that they dislike, but they do it in different ways.
One person finds alternatives to the mainstream and then advertises them and tell people: Look, here's the other way you can do it so you can avoid this terrible mess! That messaging can sometimes come across as downplaying the severity of the problem.
The second person instead wants to raise awareness of how awful the mess is, and so has to emphasize that this is a real problem.
The end result is two people that I think agree, but who appear to disagree because one wants to emphasize the severity of the problem and the other wants to emphasize potential solutions that the individual can take to address it.
Concretely, I think that's what happened here. I think everybody in this thread is pissed that single-player games would have activation and online DRM. Some people like to get around that by buying on marketplaces like GOG or playing open source games, and others want to change the policy that makes this trend possible, which means insisting that it really is a problem.
Sorry for all the meta commentary. If I got it wrong, I'd be interested to understand better!
We have a business model that I think is kind of novel (I am biased) -- we split our service into a "global identity layer"/control plane and "Relay Servers" which are open source and self-hostable. Our Obsidian Plugin is also open source.
So while we have a SaaS, we encourage our users to self-host on private networks (eg. tailscale) so that we are totally unable to see their documents and attachments. We don't require any network connection between the Relay Server and our service.
Similar to tailscale, the global identity layer provides value because people want SSO and straightforward permissions management (which are a pain to self-host), but running the Relay Server is dead simple.
So far we are getting some traction with businesses who want a best-in-class writing experience (Obsidian), google-docs-like collaboration, but local-first. This is of particular interest to companies in AI or AI safety (let's not send our docs to our competitors...), or for compliance/security reasons.
[0] https://relay.md
It's also a programming complexity problem.
A local-first app has to run on a zillion different configurations of hardware. A cloud-first app only has to run on a single configuration and the thing running on the user hardware is just a view into that singular cloud representation.
That sort of model collapses where software needs to be constantly updated and maintained lest it rots and dies as the rest of the ecosystem evolves and something dynamically linked changes by a hair. So what's left is either doing that maintenance for free, i.e. FOSS, or charging for it on a monthly basis like SAAS. We've mostly done this bullshit to ourselves in the name of fast updates and security. Maybe it was inevitable.
Or streaming media apps (like Peacock & Kanopy) reloading the previous screen from the server instead of keeping the rendered media list object resident.
95% of the content is already on the device, let's please encourage it's use.
Dirty writes can be handled easily just mark the UI dirty until the write succeeds.
My point is that we could easily fix 95% of the offline challenges with no major changes to the app design -- just better habits.
I'm pretty convinced they just want more data.
for example, apple allows offline maps, but they expire the data because they want you dependent on them.
I'm pretty sure the tesla (google) tile data has hidden motives.
I’m sure the data format of Apple Maps is constantly changing to support new features and optimizations.
if you create offline maps for some vacation away from reliable cellphone service, when 30 days passes the (gigabytes of) maps just disappear. Unusable even if you are in a remote village.
If you are fully offline, then it works as intended.
However, if you have even a tiny bit of connection, even if your connection is spotty or very slow, Google Maps refuses to use its offline data, crippling the experience and making it unusable.
I agree with the sibling comment. When I travel, I usually use 3 apps and download the offline maps of the regions I visit: Apple Maps (for iOS apps and embedded features), Google Maps, and thank god: Organic Maps.
I have also tested Gaia & All Trails maps online features, and have had mixed results with those.
I just don't think app developers take the time to test their apps in offline or poor connectivity conditions. They are used to testing procedures while using office wifi
The quality of the maps depends on the region, though. But for me it is typically good enough. I not only like the local maps, but also that I can save waypoints locally. And I can contribute things like points of interest to Open Street Map directly via the app. In my opinion, the biggest disadvantage is that there is no traffic information.
I was also pleasantly surprised to find out iOS Star Chart app (https://apps.apple.com/us/app/star-chart/id345542655) functions entirely offline. Recently used it while camping, and it just needed a GPS coordinates fix to adjust sky map to location.
https://www.comaps.app/news/2025-07-03/Announcing-Navigate-w...
The Immich "Quick Start" step 1 is mkdir and wget commands. Step 2 is "Populate the .env file with custom values"
I get it, when the prerequisites are 1) run a server and 2) have Docker installed, but this isn't inspiring confidence that local-first apps will become popular.
Obviously not every problem will have such an obvious right answer, but given the example the author chose, I don't see how you could accept any solution that doesn't produce "100" as a correct result.
You can’t know what to do without talking to the people involved, as they have to decide what makes sense for end goal. It’s mostly a social / collective action problem, not a purely technical one.
It is absolutely not "conflict-free" from the user perspective, nor is it even necessarily logical. Tools like Google Docs manage this by providing a version history so if the merge messes up, you can still go back and see each recent change to grab whatever data got lost.
Doing local-first _in a browser_ still feels like taking all the drawbacks of a browser like difficult interop with the rest of the host system and getting only one benefit (ease of distribution).
In this case, you would need two accounts, a credit and debit account, and then device A would write +20 to the credit account and -20 to the debit account, device B would write -20 to the credit account and +20 to the debit account, then using a HLC (or even not, depending on what your use-case is again), you get back to the 100 that seems from the description of the problem that it is the correct answer.
Obviously, if you are editing texts there are very different needs, but this as described is right in the wheelhouse of double-entry accounting.
The main thing to takeway is to store transactions like you mentioned (+20, -20). And in the simplest case, just apply all of them based on time.
For cross-device sync, you need a server. Either you use iCloud (limiting yourself to Apple platforms), host one (which encourages subscriptions and defeats the point of local-first) or ask users to self-host (which is difficult and error-prone).
Shareable links also need a server. You can't use iCloud for those, and if you're asking users to self-host, you now need to ensure their server is exposed publicly and has a domain. This adds yet another complication to an already complicated process, not to mention the security implications.
Security (where some users are restricted from seeing some of the data and performing some of the actions) requires much more "smarts" in the server, and makes local sync infinitely more complicated.
For local-first apps to be viable, we need a lot more primitives first. Apple provides some, but not nearly enough, and only for their own platforms. Nobody else even bothers.
The only (consumer) devices that fulfill these requirements are routers and some smart gadgets, like fridges or smart speakers. None of them are easily programmable to a sufficient degree.
This still doesn't solve the problem of sharing among users on different networks and accessing your data when you're not home.
All these problems are solvable, but they'd require massive coordination among device vendors, and coordination is one of the hardest problems out there.
Or Federated apps, again Self-Hosted.
And I think network infrastructure has been holding us back horribly. I think with something like Tailscale, we can make local-only apps or federated apps way, way easier to write.
In practice, it has an unexpected benefit. Whenever I hit a decision point where I'm not totally sure how something should behave, I can just ship it anyway without stressing about it. Later on, I can retroactively change how that action works by updating the function that processes events into state changes. It's hard to convey just how liberating this is, but trust me, this situation comes up way more often than you'd expect.
The tech is getting there though. With things like hole punching or webrtc, P2P is getting pretty easy to implement. Though it's still a challenge to implement it in an actual project.
I do believe that we're going to start seeing quality local-first software w/ great networking pop up more and more soon. I'm working on that, but I'm sure there are plenty others who are doing the same.
[1] Open-source, see my profile for info
I've found it to be a fun way to build apps.
Local-first here means starting with a local data model that syncs to the cloud from the start, rather than an app that only works online.
(I know you said not web apps, but it does have a desktop version)
So Photoshop, Blender, etc. -- these are not apps that store their data in the cloud. They're using filesystems. There's no sync. They're not local-first, they're just local.
But the Apple apps -- Notes, Music, Calendar -- they are very much local-first. Their source of truth is in iCloud when you activate that, but they fully work offline as well and then sync once there's a connection. This is completely different from e.g. Photoshop.
Ones that you have to pay for directly?
Aside from game devs it's hard for me to think of who the major players are in that space any more. And now even when the game has a single-player mode it seems to demand an Internet connection, whether for DRM reasons, "anti-cheat" (why do you care?), updates etc.
But one enables continual revenues streams and the other succumbed to extremely rampant piracy in the app space. As such, even many games on mobile are service games rather than a local single player game.
At home and in the office, we have the Internet, so it's only on the move in places where you phone doesn't work where this matters and most of us probably don't work in those places enough for it to matter.
I worked on an app a while back, a synchronising drawing app, and ran into the issues mentioned in the article that synchronising is hard and is solving a problem very few people actually have, the need to work offline.
I'm a sort of "desktop app believer" in that I think you tend to get a better UX from native desktop apps than the web, but convincing enough people to believe you or give you money for it is another matter.
And that's because (many) everyday users are not even aware that being online is not essential to perform the functionality they need from their applications. It's not that users don't care that they cannot work offline. It's that they don't even understand that requiring an internet connection is not a technical necessity, but rather an artificial limitation imposed by business interests or incompetence.
Even offline-friendly apps get spinning loaders on flaky connections. Google Docs will be stuck checking to see if a doc has been updated before it loads it, and will only actually open it when I turn on Airplane Mode. Similarly, Spotify will be stuck loading a saved playlist or album because it's trying to load extra information it loads when connected to the internet, and again only Airplane Mode will skip that so it knows it's offline-only.
Flaky connections are the bane of existence of apps that work offline, either because apps want to load extra online-only data whenever possible, or simply ensure everything is synced before taking a big action.
We used to have offline everything and everything just worked. Now we are forced to sync with the cloud weather we like it or not. A subscription model shows a continuous cash flow and businesses like that.
Other vendors like Powersync and ElectricSQL have a similar offering but are upfront about it. And at least in Powersync’s case (don’t know about Electricsql) you can also run their offering yourself.
So the question is whether it's possible to build software that adheres to the local-first principles using sqlite-sync.
edit: I'm aware people are using the term "local-first" very loosely, so perhaps my reply here is a bit off-topic
p.s. yes you can self-host ElectricSQL
p.p.s. I really need to keep my list of "sqlite sync" things updated: I have SQLSync [2], SQLiteSync [3] and now SQLite-Sync [4]. Simple!
[1] https://www.inkandswitch.com/essay/local-first/
[2] https://github.com/orbitinghail/sqlsync
A simpler approach works surprisingly well:
Store atomic mutations locally (Redux-like) in SQLite.
Sync those mutations to a central server that merges with last-writer-wins.
Handle the few conflicts that do occur through clear ownership rules and some UI/UX design.
This makes local-first behave more like Git: clients work offline, push their “commits,” and the server decides the truth. Most of the complexity disappears if the data model is designed with collaboration and ownership in mind.
Still, where a simpler approach gets tricky is if you only want to sync a subset of the backend database to any client's SQLite
Our recent work on Loro CRDTs aims to bridge this gap by combining them with common UI state patterns. In React, developers can keep using `setState` as usual, while we automatically compute diffs and apply them to CRDTs; updates from CRDTs are then incrementally synced back into UI state [1]. This lets developers follow their existing habits without worrying about consistency between UI state and CRDT state. Paired with the synchronization protocol and hosted sync service, collaboration can feel as smooth as working with a purely local app. We’ve built a simple, account-free collaborative example app[2]. It only has a small amount of code related to synchronization; the rest looks almost the same as a purely local React app.
Thanks for your great work with loro
In theory, loro-mirror could also be used to integrate Loro with other rich-text editors, but that wasn’t its original design goal and it may need further refinement to work well.
Realistically the reason is probably that it's easier to make changes if you assume everything is phoning home to the mother ship for everything.
Also, an unrelated nit: "Why Local-First Apps Haven’t Become Popular?" is not a question. "Why Local-First Apps Haven’t Become Popular" is a noun phrase, and "Why Haven't Local-First Apps Become Popular?" is a question. You wouldn't say "How to ask question?" but instead "How do you ask a question?"
I think the truth of your statement is more that free software tends towards what you might call "offline" software (e.g., software that doesn't sync or offer real-time collaboration), because there's more friction for having a syncing backend with free software.
Your examples are all programs that predate mobile, even though they are available on mobile (are they local-first on mobile too?).
(And yes, they're all local first on mobile as well.)
(Also Notes and Photos were mobile apps on the iPhone first [not that it really matters, just FYI].)
Apple continues to release new apps under this model today (i.e., local first), e.g., https://en.wikipedia.org/wiki/Freeform_(Apple). In my mind, the evidence just points to Apple thinking local-first is the best approach for the software on their devices.
(And, increasingly, entertainment and services.)
Software is a positive complement to those revenue sources.
> Each update gets a timestamp (physical or logical).
> When two devices write to the same field, the update with the latest timestamp wins.
Please also have a robust synced undo feature, so it's easy to undo the thing you don't want that gets written. Apps that sync often seem to be stingy about how much "undos" they store/sync (if any).
Depends on the granularity of updates. Did the last changes get sent immediately? Are they gated by a save button? Are they periodically pushed?
Some of those don’t need a durable undo, but the rest definitely benefit, and undo has other uses.
The syncing issue is also handled better by making the logical unit that gets changed as small as possible. If you have two people editing a document, instead of locking the document, and wiping out changes from other people, think of it as a series of edits to a paragraph, or smaller a sentence, or even the exact word being changed. If someone has text highlighted, then lock anyone else out from editing it because there is a high chance they're going to erase it or paste over it.
Lastly, as AI moves forward, it would be an interesting experiment to start having AI auto-resolve conflicts in the small. (user has been replacing the word taco with burrito, and two users started typing in the same spot TaBurrcoito. Maybe Burrito would win.
If that was deterministic, that was a very bad idea.
But also nowadays you want to have information from other computers. Everything from shared calendars to the weather, or a social media entry. There's so much more you can do with internet access, you need to be able to access remote data.
There's no easy way to keep sync, either. Look at CAP theorem. You can decide which leg you can do without, but you can't solve the distributed computing "problem". Best is just be aware of what tradeoff you're making.
Git has largely solved asynchronous decentralized collaboration, but it requires file formats that are ideally as human understandable as machine-readable, or at least diffable/mergable in a way where both humans and machines can understand the process and results.
Admittedly git's ergonomics aren't the best or most user friendly, but it at least shows a different approach to this that undeniably works.
The merge workflow is not inherently complicated or convoluted. It's just that git is.
When dvcses came out there were three contendors: darcs, mercurial and git.
I evaluated all three and found darcs was the most intuitive but it was very slow. Git was a confused mess, and hg was a great compromise between fast and having a simple and intuitive merge model.
I became a big hg advocate but I eventually lost that battle and had to become a git expert. I spent a few years being the guy who could untangle the mess when a junior messed up a rebase merge then did a push --force to upstream.
Now I think I'm too git-brained to think about the problem with a clear head anymore, but I think it's a failure mostly attributable to git that dvcs has never found any uptake outside of software development and the fact that we as developers see dvcs as a "solved problem" outside more tooling around git is a failure of imagination.
What makes merging in git complicated? And what's better about darcs and mercurial?
(PS Not disagreeing just curious, I've worked in Mercurial and git and personally I've never noticed a difference, but that doesn't mean there isn't one.)
[0] Where CRDTs spent most of a couple of decades shooting for the stars and assuming "Conflict-Free" was manifest destiny/fate rather than a dream in a cruel pragmatic world of conflicts, Darcs was built for source control so knew emphatically that conflicts weren't avoidable. We're finally at the point where CRDTs are starting to take seriously that conflicts are unavoidable in real life data and trying new pragmatic approaches to "Conflict-Infrequent" rather that "Conflict-Free".
Auto-merging code is also a double-edged sword - just because you can merge something at the VCS-level does not mean that the result is sensible at the format (programming language) or conceptual (user expectation) levels.
It wasn't just "auto-merging" that is darcs' superpower, it's in how many things that today in git would need to be handled in merges that darcs wouldn't even consider a merge, because its data structure doesn't.
Darcs is much better than git at cherry picking, for instance, where you take just one patch (commit) from the middle of another branch. Darcs could do that without "history rewriting" in that the patch (commit) would stay the same even though its "place in line" was drastically moved. That patch's ID would stay the same, any signatures it might have would stay the same, etc, just its order in "commit log" would be different. If you later pulled the rest of that branch, that also wouldn't be a "merge" as darcs would already understand the relative order of those patches and "just" reorder them (if necessary), again without changing any of the patch contents (ID, signatures, etc).
Darcs also has a few higher level patch concepts than just "line-by-line diffs", such as one that tracks variable renames. If you changed files in another branch making use of an older name of a variable and eventually merge it into a branch with the variable rename, the combination of the two patches (commits) would use the new name consistently, without a manual merge of the conflicting lines changed between the two, because darcs understands the higher level intent a little better there (sort of), and encodes it in its data structures as a different thing.
Darcs absolutely won't (and knows that it can't) save you from conflicts and manual merge resolution, there are still plenty of opportunities for those in any normal, healthy codebase, but it gives you tools to focus on the ones that matter most. Also yes, a merge tool can't always verify that the final output is correct or builds (the high level rename tool, for instance, is still basically a find-and-replace and can be over-correct false positives and and miss false negatives). But it's still quite relevant to merges the types of merges you need to resolve in the first place, and how often they occur, and what qualifies as a merge operation in the first place.
Though maybe you also are trying to argue the semantics of what constitutes a "merge", "conflicts", and an "integration"? Darcs won't save you from "continuous integration" tools either, but it will work to save your continuous integration tools from certain types of history rewriting.
"At the end of the day" the state-of-the-art of VCS on-disk representation and integration models and merge algorithms isn't a solved problem and there are lots of data structures and higher level constructs that tools like git haven't applied yet and/or that have yet to be invented. Innovation is still possible. Darcs does some cool things. Pijul does some cool things. git was somewhat intentionally designed to be the "dumb" in comparison to darcs' "smart", it is even encoded in the self-deprecating name (from Britishisms such as "you stupid git"). It's nice to remind ourselves that while git is a welcome status quo (it is better than a lot of things it replaced like CVS and SVN), it is not the final form of VCS nor some some sort of ur-VCS which all future others will derive and resembles all its predecessors (Darcs predates git and was an influence in several ways, though most of those ways are convenience flags that are easy to miss like `git add -p` or tools that do similar jobs in an underwhelming fashion by comparison like `git cherry-pick`).
For local-first async collaboration on something that isn't software development, you'd likely want something that is a lot more polished, and has a much more streamlined feature set. I think ultimately very few of git's chafing points are due to its model of async decentralized collaboration.
Apparently 'jujutsu' makes the git workflow a bit more intuitive. Its something that runs atop git, although I don't know how much it messes up the history if you read it out with plain git.
All in all I'm pretty happy with git compared to the olden days of subversion. TortoiseSVN was a struggle haha.
People say git is too "complex" or "complicated" but I never saw end users succeeding with CVS or Mercurial or SVN or Visual Sourcesafe the way they do with Git.
"Enterprise" tools (such as business rules engines) frequently prove themselves "not ready for the enterprise" because they don't have proper answers to version control, something essential when you have more than one person working on something. People say "do you really need (the index)" or other things git has but git seemed to get over the Ashby's law threshold and have enough internal complexity to confront the essential complexity of enterprise version control.
Yes, but then you are not using a "local first" tool but a typical server based workflow.
Not saying this would be in any way easy, but I'm also not seeing any inherent obstacles.
> It requires file formats that are ideally as human understandable as machine-readable, or at least diffable/mergable in a way where both humans and machines can understand the process and results.
What you're proposing is tracking and merging operations rather than the result of those operations (which is roughly the basis of CRDTs as well).
I do think there's some problems with that approach as well though (e.g., what do you do about computationally expensive changes like 3D renders?). But for the parts of the app that fit well into this model, we're already seeing collaborative editing implemented this way, e.g., both Lightroom and Photoshop support it.
To be clear though, I think the only sensible way to process merges in this world is via a GUI application that can represent the artifact being merged (e.g., visual/audio content). So you still wouldn't use Git to merge conflicts with this approach (e.g., a simple reason why is that what's to stop an underlying binary asset that a stack of operations is being applied to from having conflicting changes if you're just using Git?). Even some non-binary edits can't be represented as "human readable" text, e.g., say adding a layer of a vector drawing of rabbit.
Three-way merges in general are easier to write than the CRDTs as the article suggests. They are also far more useful than just the file formats you would think to source control in get; it's a relatively easy algorithm to apply to any data structure you might want to try.
For a hobby project I took a local-first-like approach even though the app is an MPA, partly just because I could. It uses a real simple three-way merge technique of storing the user's active "document" (JSON document) and the last known saved document. When it pulls an updated remote "document" it can very simply "replay" the changes between the active document and the last known saved document to the active document to create a new active document. This "app" currently only has user-owned documents so I don't generally compute the difference between the remote update and the last saved to mark conflicted fields to the user, but that would be the easy next step.
In this case the "documents" are in the JSON sense of complex schemas (including Zod schemas) and the diff operation is a lot of very simple `===` checks. It's an easy to implement pattern and feels smarter than it should with good JSON schemas.
The complicated parts, as always, are the User Experience of it, more than anything. How do you try to make it obvious that there are unsaved changes? (In this app: big Save buttons that go from disabled states to brightly colored ones.) If you allow users to create drafts that have never been saved next to items that have at least one save, how you visualize that? (For one document type, I had to iterate on Draft markers a few times to make it clearer something wasn't yet saved remotely.) Do you need a "revert changes" button to toss a draft?
I think sometimes using a complicated sync tool like CRDTs makes you think you can escape the equally complicated User Experience problems, but in the end the User Experience matters more than whatever your data structure is and no matter how complicated your merge algorithm is. I think it's also easy to see all the recommendations for complex merge algorithms like CRDTs (which absolutely have their place and are very cool for what they can accomplish) and miss that some of the ancient merge algorithms are simple and dumb and easy to write patterns.
So, sure, if you are saying "people trained to use git" there, I agree. And you wind up having all sorts of implicit rules and guidelines that you follow to make it more manageable.
This is a lot like saying roads have solved how to get people using dangerous equipment on a regular basis without killing everyone. Only true if you train the drivers on the rules of the road. And there are many rules that people wind up internalizing as they get older and more experienced.
Fortunately, a lot of what chafes with git are UX issues more than anything else. Its abstractions are leaky, and its default settings are outright bad. It's very much a tool built by and for kernel developers with all that entails.
The principle itself has a lot of redeemable qualities, and could be applied to other similar syncing problems without most of the sharp edges that come with the particular implementation seen in git.
imagine asking a normie to deal with a merge conflict
It's literally entirely on a computer. If that somehow makes it harder to answer basic human questions about the complex things we're using it for, well that means we've got a problem folks.
The problem is with comprehensibility, and it's entrenched (because the only way for a piece of software to outlive its 50 incompatible analogs and reach mass recognition is to become entrenched; not to represent its domain perfectly)
The issue lies in how the tools that we've currently converged on (e.g. Git) represent the semantics of our activity: what information is retained at what granularity determines what workflows are required of the user; and thence what operations the user comes to expect to be "easy" or "hard", "complex" or "simple". (Every interactive program is a teaching aid of itself, like how when you grok a system you can whip together a poor copy of it in a couple hours out of shit and sticks)
Consider Git's second cousin the CRDT, where "merges" are just a few tokens long, so they happen automatically all the time with good results. Helped in application context by how a "shared editor" interface is considerably more interactive than the "manually versioned folder" approach of Git. There's shared backspace.
Git was designed for emailing patches over dialup, there it obviously pays to be precise; and it's also awesome at enabling endless bikeshedding on projects far less essential than the kernel, thanks to the proprietary extension that are Pull Requests.
Probably nobody has any real incentive to pull off anything better, if the value proposition of the existing solution starts with "it has come to be expected". But it's not right to say it's inherently hard, some of us have just become used to making it needlessly hard on ourselves, and that's whose breakfast the bots are now eating (shoo, bots! scram)
To be precise, these apps where not local-_first_, they where local-_only_. Local-first implies that the app first and foremost works locally, but also that it, secondly, is capable of working online and non-locally (usually with some syncing mechanism).
Sure there is, you just gotta exploit the multiverse[1]. Keep all the changes in their own branch aka timeline, and when there's some perceived conflict you just say "well in the timeline I'm from, the meeting was moved to 4pm".
[1]: https://www.reddit.com/r/marvelstudios/comments/upgsuk/expla...
Do I? What sort of information ...
> shared calendars
OK yes that would be a valid use, I can imagine some stressed executive with no signal in a tunnel wanting to change some planned event, but also to have the change superceded by an edit somebody else makes a few minutes later.
> the weather
But I don't usually edit the weather forecast.
> a social media entry
So ... OK ... because it's important that my selfie taken in a wilderness gets the timestamp of when I offline-pretend-posted it, instead of when I'm actually online and can see replies? Why is that? Or is the idea that I should reply to people offline while pretending that they can see, and then much later when my comments actually arrive they're backdated as if they'd been there all along?
At work: I write code, which is in version control. I write design documents (that nobody reads), and put them on a shared computer. I write presentations (you would better off sleeping through them...) and put them on a share computer. Often the above are edited by others.
Even at home, my grocery list is shared with my wife. I look up recipes online from a shared computer. My music (that I ripped from CDs) is shared with everyone else in the house. When I play a game I wish my saved games were shared with other game systems (I haven't had time since I had kids, more than 10 years ago). When I take notes about my kid's music lessons they are shared with my wife and kids...
It's a far, far more complicated mental model than simply posting it. It'd be a huge barrier for normal users (even tech-savvy users, I'd say). People want to post it online and that's it. No one wants an app what requires its users to be aware of syncing state constantly unless they really have no choice. We pretend we can step on gas instead of mixing the gas with air and ignite it with a spark plug until we need to change the damn plug.
It was the first practical manner to downsize mainframe applications.
> Local-first was the first kind of app. Way up into the 2000s, you'd use your local excel/word/etc, and the sync mechanism was calling your file annual_accounts_final_v3_amend_v5_final(3).xls
With the exception of messenger clients, Desktop apps are mostly "local-first" from day one.
At the time you're beginning to think about desktop behavior, it's also worth considering whether you should just build native.
There's no easy way to merge changes, but if you design around merging, then syncing becomes much less difficult to solve.
It started with single computers, but they were so expensive nobody had them except labs. You wrote the program with your data, often toggling it in with switches.
From there we went to batch processing, then shared computers, then added a networking, with file sharing and RPC. Then the personal computer came and it was back to toggling your own programs, but soon we were running local apps, and now our computers are again mostly "smart terminals" (as opposed to dumb terminals), and the data is on shared computers again.
Sometimes we take data off the shared computer, but there is no perfect solution so distributed computing and since networks are mostly reliable nobody wants that anyway. What we do want is control of our data and that we don't get (mostly)
My last job was balls deep in the Google ecosystem, and all the collaborative editing, syncing and versioning and whatnot did nothing to stop that practice.
On a related note, I used to hate Gmail (I still do, but I used to too), until I had to use Outlook and all the other MS crap at my new job. Jesus christ. WTF even is Teams? Rhetorical question; I don't care.
For example my local apps: Synthing syncs the files between my computer and phone for Note taking(just markdown and org files) obsidian on my phone, emacs/vim on my PC. Todo and reminders: org mode in emacs (desktop) orgzly on mobile. Password manager: KeePassxc desktop, keepassdx mobile. Calendar: just sync the ics file. Photos: just sync files use the default app. I can continue with this with every app, I don't know why people overcomplicate things
Syncthing uses "disovery servers" so no need for public IP's or wireguard or anything like that (you can set up your own if you don't trust syncthing https://docs.syncthing.net/users/stdiscosrv.html but they're only used for that discovery part, which is one of the main hurdles when you start thinking about peer-to-peer systems).
(However, I use Fastmail's calendar, for handling invites and since it keeps my subscriptions up-to-date. Considering the move from bitwarden to keepassxc.)
For photos and some other type of data this likely isn't much of a problem. But for more complex data it definitely is.
It seems like most of those are apps where I'm creating or working on something by myself and then sharing it later. The online part is almost the nice-to-have. A lot of other apps are either near-real-time-to-real-time communication where I want sending to succeed or fail pretty much immediately and queueing a message for hours and delivering it later only creates confusion. Or the app is mostly for consuming and interacting with content from elsewhere (be that an endless stream of content a la most "social media", news, video, etc. or be it content like banking apps and things) and I really mostly care about the latest information if the information is really that important at all. The cases in those apps where I interact, I also want immediate confirmation of success or failure because it's really important or not important at all.
What are the cases where offline-first is really essential? Maybe things that update, but referencing older material can be really useful or important (which does get back to messaging and email in particular, but other than something that's designed to be async like email, queueing actions when offline is still just nice-to-have in the best cases).
Otherwise the utility of CRDTs, OT, et al. is mostly collaborative editing tools that still need to be mostly online for the best experience.
It is interesting. I've thought about things I don in non-messaging apps (which are online0first for obvious reasons), and all of them create something, which can be EXPORTED to on-line presence, but doesn't require connected app.
Code? I write it locally and use separate app to share it: git. Yes, code is collaborative creation (I'm working in the team), but it is still separate tool and I like it, as I control what I'll publish for my colleagues.
Photos? Of course I want to share result, but I'm working on RAW files with non-destructive editing and I want to share final bitmap (as JPEG) and not RAW data and editing steps.
Same with music, if I create one (I doesn't).
Texts must be polished in solitude and presented as final result (maybe, as typographically set one, as PDF).
All my "heavy" applications are and should be offline-first!
I think most real-world applications fall under either "has to be done online", or "if there are conflicts, keep both files and let the user figure it out". Trying to automatically merge two independent edits can quickly turn into a massive mess, and I really don't want apps to do that automagically for me without giving me git-like tooling to fix the inevitable nightmare.
that's why local first also makes sense for server bound applications. it's not offline first, but by moving online activities into the background, all my interaction with the site would be snappy and smooth, and i could read and comment and move on to the next action without waiting for the browser to reload the page
The technology behind Groove now powers OneDrive and Microsoft 365.
Notes was replaced by the web (and Outlook). Notes was, IMHO, ahead of its time. It was one of the first client-server systems where the client was treated as a full peer in the network. You could work offline for as long as you wanted and then the client would automatically synchronize with the server. It had military-grade encryption, a built-in development environment, integrated full-text search, and programmable agents for scheduled data processing, alerting, etc.
But the web was much cheaper and benefited from network scaling laws (the more sites, the more value it accrued). The web is a perfect example of "worse is better". The complexity of Lotus Notes kept the price high (both financially and in terms of time-commitment).
For Groove we doubled-down on peer-to-peer synchronization. Notes had synchronization at the "note" level. If two people edited the same note while offline then there were conflicts that had to be resolved manually. In contrast, Groove had custom synchronization systems for different kinds of data. For text files we could synchronize at the character level. Other data structures could synchronize at whatever level was appropriate.
We used a change-log merge system, not too different from block chain.
The problem with Groove was that the advantages (offline editing) never compensated for the disadvantages (lower performance, lack of visibility in sync state, and difficulty in onboarding).
The use cases that really needed Groove were rare, and not enough to build a viable business.
And it will continue to do that forever.
Source: when we lose power and the machine restarts unexpectedly, I die a little inside when it goes to the windows set up screen just because I haven't signed in to a Microsoft account.
This should change over time; the libraries and documentation keep getting better.
I recommend Automerge 3.0’s documentation as an introduction to the concepts and how to bridge with traditional data. https://automerge.org/docs/hello/
In greenfield it's easier (so long as you have the grit to build the base pattern); Events get put into tables (TBH this can be optional, but if you're new to it just do it b/c it will make debugging easier,) and if you want a friendly clean 'view' state you have some form of map-reduce replication running on the event set.
And yeah you can even remix that idea to work on 'existing' tables but it's gonna be more work and you'll probably want some form of optimistic concurrency check...
It's not always offline. We do use online services like firebase for auth and subscription, and some service to fetch commodity prices etc, but rest of the data is stored in browser storage (sqlite) and backed to local disk and dropbox. We also syncs data across devices, always encrypting data in transit. We use Evolu for sync.
For most personal applications, this model seems to fit. If you figure out sync, the development model is actually nicer than web apps. There is no need for dealing with calls over network for each action. It does make some things more difficult. Debugging, migrations etc.
Also I don't understand why so many people on HN are concentrating on the simultaneous editing scenario, for most ordinary people this is actually quite a rare event especially in their private lives. Google Keep on Android seems to work pretty well in his context my family uses it to share shopping lists and other notes very successfully even hough several of us are online only intermittently.
Apple comes close with CloudKit, in that it takes the backend service and makes it generic, basically making it an OS platform API, backed by Apple's own cloud. Basically cloud and app decoupled. But, the fundamental issue remains, in that it's proprietary and only available on Apple devices.
An open source Firebase/CloudKit-like storage API that requires no cloud service, works by p2p sync, with awesome DX that is friendly to regular developers, would be the holy grail for this one.
Dealing with eventually consistent data models is not so unusual these days, even for devs working on traditional cloud SAAS systems, since clouds are distributed systems themselves.
I would be very happy to see such a thing built on top of Iroh (a p2p network layer, with all the NAT hole punching, tunnelling and addressing solved for you) for example, with great mobile-first support. https://github.com/n0-computer/iroh
Open source, uses object storage without a web server dependency, syncs, and has great DX.
While this may be true, the central issue is a different one: most users and/or developers are not very privacy-conscious, so they don't consider it to be worth the effort to solve the problems that go in hand with such distributed systems.
Someone could write a whole slew of changes locally and someone else can eliminate all their work because they have an outdated copy locally and they made a simple update overriding the previous person's changes.
That's why git has merges and conflicts - it doesn't want to lose changes and it can't automatically figure out what should stay in case of a conflict.
Compared to what?
All you need is a way to resolve conflicts and you can serialize any distributed set of actions to a log.
If all you need to solve a problem is something impossible, then you haven't solved it.
Everything is hard if you don't know how to do it.
I think that this is much superior to using fake apps that live on some web server. It comes with great drawbacks even when it is on the web server of the app manufacturer. Ten times more pain if I have to host it myself.
Self hosting is an unsurpassable mountain for 99% of people who need to use computers. The risk to security and data loss is much higher than from syncing your apps through iCloud or through the app manufacturer.
> Why haven't local-first apps become popular? (
I think that the title wants to be is "Why haven't more developers written local-first apps for their syncing solution?" because the the answer to title itself is because users don't care. Users (most) want apps that sync between their phone, their tablet, and their laptop/desktop. Up to some point, they don't care how it happens, just that it does and that they don't have to give it a second thought.
I think there should be way more local apps with sync capabilities. I haven’t finished the sync feature in WithAudio and you have very nice ideas there. Specially the eventual consistency. That’s what will work.
But I must say for sure the most difficult part of local apps is debugging customer issues. For someone who is used to logs and traces and metrics and most of users using a one version of the code in the backend, debugging an issue in customers computer on an old version without much insight (without destroying all your premises of privacy) is very challenging.
if i develop it as a webapplication, then i can do all the work on my computer, test with various browsers and deliver a working result. if the customer has issues, i can likely reproduce them on my machine.
but if it was a desktop application, my feeling was that testing would be a nightmare. i would have to set up a machine like my client, or worse visit the client and work with them directly, because my own machine is just to different from what the client uses. also not to forget distribution and updates
in short: web -> easy. desktop -> difficult.
"Local-first apps" are the worst of everything - crappy, dumbed down web UI; phoning home, telemetry, and other privacy violations; forced upgrades; closed source, etc.
At work, I don't have a choice, so it's Google Docs or Office 365 or whatever. And in that context it actually makes sense to have data stored on some server somewhere because it's not really my data but the company's. But at home I'll always choose the strictly offline application and share my data and files some other way.
What does any of this have to do with local first? Most online only apps have this stuff too.
which apps are you talking about here? that description doesn't make any sense to me.
The only “big” local first app I’m aware of is Linear.
Most uses of the term local-first I see regularly mean to say, "an app that doesnt require 3rd party servers outside of your control to function", within some level of reason. Sometimes agnostic to how it's data is synced, sometimes meaning its an exercise left to the user entirely, sometimes meaning fully self-hosted and hardly local to the device being used to access the app.
> phoning home, telemetry, and other privacy violations; forced upgrades; closed source, etc.
This describes proprietary software developed by capitalist companies. This has nothing to do with local first.
- There was never a budget for CRDT's
- Conflicts were never our primary focus, instead our focus were business problems
- Event-sourced arch + offline first app was quite a fun. Basically I've recorded all the events in sequence in SQLite, queued them up when there was a connection and had network retry policy in place + reverting an event locally if retry failed n-th amount of times.
They are misaligned here. What's good for the app user is not necessarily good for the people making the app.
I know several companies whole second or third round of investment was very much conditional on them making the pivot from "on premise" to "SASS". On paper, an on-premise app that I can manage on my own infrastructure seems more interesting for me as a consumer. But for the investors of those companies I just mentioned, having a SASS offering is seen as "having a bigger hold on your customers".
Social media could allow you to make posts as a "draft" and automatically send it when you have a connection think of a email outbox. Or even give you a notification if after syncing with the master and it turns out the comment you replied to changed.
If you look at the web a lot of older (fundamental)protocols and applications have local-first build in. Often the design requirements required communication over a connection that is not as available. A few I can think of of HTTP, EMAIL, FINGER, GOPHER, FIDONET, NEWGROUP and more. A shared state is managed for a lot of different domains (code, gaming, chat, message boards) so I feel like it is already quite a solved problem, but there is no one size fits all solution. IMHO that's the sane thing to do for a networked application as you can never grantee that either party is available, and you want to still serve your user the best you can.
It can also have huge benefits for the data provider, especially at scale. - You can lower your bandwidth required drastically. - You can keep a consistent state for your user. - If you are evil you can send a lot more telemetry data or valuable (harvested) data instead.
the LWW is only really useful if you have a value where you can discard the previous updates for the latest, it's a bit like using UDP instead of TCP for communicating your position in a multiplayer game. Or if you don't mind forcing your user to resubmit.
No clocks or CRDTs are going to automatically fix this. The right solution could be my edits, or your new replacement, or some merge, but there isn't any automatic way to do this is there?
I'd like to use DuckDB to remotely query Parquet. Unfortunately I can't use it in an iOS app because I'd have to work around the dynamic loading of extensions and bundle OpenSSL to support Httpfs in a static build. I'm building my own library instead.
That's just one example. I'd like to use certain LGPL licensed libraries but I can't because the legal risks are too high, as is the cognitive load in dealing with license uncertainty.
Neither of these things are an issue for web-apps.
I think the economics for local-first software could really work out for businesses that use significant compute. Cloud-compute is not cheap and comes with significant financial tail-risk.
Subscription-based software made a lot of products affordable. $49.95 a month indefinitely is a lot easier for many small businesses to sustain than a lump sum of $1,500 for a software package.
Considering how undercapitalized most small businesses are, it's not hard to see why many of them may prefer to rent the software instead of buying it.
Local-first and decentralized apps haven't become popular because SaaS has a vastly superior economic model, and more money means more to be invested in both polish (UI/UX) and marketing.
All the technical challenges of decentralized or local-first apps are solvable. They are no harder than the technical challenges of doing cloud at scale. If there was money in it, those problems would be solved at least as well.
Cloud SaaS is both unbreakable DRM (you don't even give the user the code, sometimes not even their data) and an impossible to evade subscription model. That's why it's the dominant model for software delivery, at least 90% of the time. The billing system is the tail that wags the dog.
There are some types of apps that have intrinsic benefits to being in the cloud, but they're the minority. These are apps that require huge data sets, large amounts of burstable compute, or that integrate tightly with real world services to the point that they're really just front-ends for something IRL. Even for these, it would be possible to have only certain parts of them live in the cloud.
> The long-term direction is for Epicenter to become a foundational data framework for building apps where users truly own and control their own data. In other words, the Epicenter framework becomes an SSO for AI applications. Users use Epicenter to plug into any service, and they'll own their data, choose their models, and replace siloed apps with interoperable alternatives. Developers will use our framework to build highly customized experiences for said users. To pursue that goal seriously, we also need a sustainable model that honors our commitment to open source.
> ...The entire Epicenter project will be available under a copyleft license, making it completely free for anyone building open-source software. On the other hand, if a company or individual wants to incorporate the framework into their closed-source product, they can purchase a license to build with Epicenter without needing to open source their changes and abide by the copyleft terms. This is the model used by Cal.com, dub.sh, MongoDB, etc.
On the business model, dual license works if you de‑risk the integration: stable plugin ABI, permissive SDKs, and paid “closed‑source embedding” tier with SLAs and on‑prem support. Where I’ve seen revenue actually land: (1) paid sync/relay with zero data retention, (2) enterprise key management and policy controls, and (3) priority support/migration bundles. One caution: “privacy” alone doesn’t convert; solve a concrete ops pain. I built CrabClear to handle the obscure brokers others miss, and the lesson was the same—privacy sells when it eliminates a specific, recurring headache. If Epicenter can quantify one such headache and make it vanish out‑of‑the‑box, the model becomes much easier to sustain.
There’s also an upcoming generation that doesn’t know what a filesystem is which also doesn’t help matters.
This is why I sometimes think it's hopeless. For a while there -- 90s into the 2000s -- we were building something called "computer literacy." Then the phones came out and that stopped completely. Now we seem to have inverted the old paradigm. In that era people made jokes about old people not being able to use tech. Today the older people (30s onward) are the ones who can use tech and the younger people can only use app centric mobile style interfaces.
The future is gonna be like: "Hey grandpa, can you help me figure out why my wifi is down?"
Local first tends to suck in practice. For example, Office 365 with documents in the cloud is so much better for collaborating than dealing with "conflicted copy" in Dropbox.
It sucks that you need an internet connection, but I think that drawback is worth it for never having to manually merge a sync conflict.
That has nothing to do with where the code lives and runs. There are unique technical challenges to doing it all at the edge, but there are already known solutions to these. If there was money in it, you'd have a lot of local first and decentralized apps. As I said, these technical challenges are not harder than, say, scaling a cloud app to millions of concurrent users. In some cases they're the same. Behind the scenes in the cloud you have all kinds of data sync and consistency enforcement systems that algorithmically resemble what you need for consistent fluid interaction peer to peer.
When multiple people work on a document at the same time, you will have conflicts that will become very hard to resolve. I have never seen a good UI for resolving non-trivial changes. There is no way to make this merging easy.
The only way to avoid the merge problem is to make sure that the state is synchronised before making changes. With cloud based solutions this is trivial, since the processing happens on the server.
The local first variant of this would be that you have to somehow lock a document before you can work on it. I worked on a tool that worked like that in the early 2000s. Of course that always meant that records remained locked, and it was a bit cumbersome. You still needed to be online to work so you could lock the records you needed.
There are multiple ways to do this, like CRDTs plus raft based leader signaling for conflict resolution. The latter signaling requires almost no bandwidth. Raft based time skew adjustment works too if your problem domain can accept a small amount of uncertainty.
Like I said a lot of these same kinds of algorithms are used cloud side. All the big cloud stuff you use is a distributed system. Where the code runs is irrelevant. The cloud is just another computer.
There is no way to tell which of the changes should win.
That's why most applications decided to require users be online for edits. when you have to be online, the chance of simultaneous edits becomes so small that you can just show an error message instead of trying to merge.
The online requirement also ensures that you are notified of conflicts immediately, which is vastly preferable to users. Nothing worse than working on a document for hours and discovering someone else also worked on the same document and now you have two edited copies that someone needs to consolidate.
That's the reason why offline first is becoming increasingly unpopular.
Something that should be local and snappy is just an awful experience.
That said, 'local' can mean a number of different things. On-device local, LAN local, intranet local... You get the idea. I chose to go with an approach of: 'assume resources are constrained and build for that'.
The result was a local-first agentic system (https://github.com/dibrale/Regions) that uses explicit resource sharing and execution patterns to make use of arbitrarily distributed compute. That way, local can be whatever I want it to be, so long as there's an endpoint.
This is true, but any time there's more than one computer involved it's a distributed system. It doesn't matter if you're "local first" or not.
Plenty of apps that resolve everything server side do a terrible job handling conflicts.
That obsession with Google Docs-like collaborative real-time text editing, a pretty marginal use case, derails the progress from where local-first apps really need it:
- offline-enabled, rather than realtime/collaborated
- branching/undoing/rebasing, rather than combining edits/messages
- help me create conflict-aware user workflows, rather than pursue conflict-free/auto-converging magic
- embeddable database that syncs, not algorithms or data types
CRDT research gives us `/usr/bin/merge` when local-first apps actually need `/usr/bin/git`. I don't care much how good the merge algorithm is, I need what calls it.
The main problem with any sync system that allows extensive offline use is in communicating how the reconciliation happens so users don't get frustrated or confused. When all reconciliation happens as a black box your app won't be able to do a good job at that.
If your using the "local" shared storage, then you're on the hook for any failure or setup, so there is a huge amount of debug and reputational damage in store for not very much gain.
If you are supporting multi device makers, and a normal audience, (ie people who don't know what CRDTs are) then you doing the hard work is far easier.
And thats before we get into ACLs for sharing.
Recently I went to the grocery store and presented with no signal had to try to recall my grocery list from memory. In all my years using my own app I think this is the first time I'd ever wished it were "local first"
I've been exploring how to build a sync layer around SQLite for the last 5 years as part of LiveStore and settled on embracing event sourcing following a similar architecture to Git but for your application data.
An alternative is "using a server that the user has", e.g. saving to their iCloud/Dropbox/Google Drive/GitHub/etc.
(There used to be old notes applications which would save your notes in an IMAP folder on your email server; almost every user of your app will have email.)
Offline first apps 'sound like the future'? I agree they're far better than the trash we have now, but it's not like we can't build them now.
We should be building them now. The web was never meant to be an app delivery platform :(
Unfortunately this extension "is tightly integrated with SQLite Cloud." It doesn't support peer-to-peer syncing or self-hosting a central source of truth. The project is really just a client for the sqlite.ai cloud service.
Luckily this is a use case where conflict resolution is pretty straightforward (only you can update your workout data, and Last Write Wins)
[1] https://apps.apple.com/us/app/titan-workout-tracker/id644949...
[1] GitHub: https://github.com/hasanhaja/tasks-app/ [2] Deployed site: https://tasks.hasanhaja.com/
I guess I should bring my devices back to exactly 1 device. Or just take a subscription on one service.
Also I believe the original comment is right as your browser (HTTP) operates fundamentally on a request reply basis. You request resources, you receive an answer, while you are displaying the most recent answer the state on the server might change. You can have a browser that caches the resources for you and only retrieve the new state after for example a timeout or for example a archiving proxy.
A browser is (in my definition) a tool to display what you call a websites, usually a collection of html/css/js resources. One of the options is to retrieve the resources through the network, if you want the latest news for instance. But it is not required and that makes it local-first in my view. I don't think local first means the app can not connect or sync with a remote server.
In the same way as saying we live on earth doesn't mean we are not in space, earth is in space and we are on earth. It is not mutually exclusive.
- What if I don't have that device? - How do I reliably sync between devices? - How do I deal with local storage limits of a device?
Silverbullet has become very nearly my illustration of the perfect app, because it has a local, offline feature but syncs back to a server controlled by me. The weakness with SB specifically is any limits on browser storage, though that's less likely an issue for a note-taking tool that is, for me, 99.9% text.
Compare Logseq, which used to be browser-based and self-hostable, to their more recent "local-first, app-based" model, with a $15/mo charge to sync and severe usability restrictions in a world where I cannot install arbitrary software at work.
So, local-first has for me become synonymous with inconvenience, proprietary, and revenue channel for the dev rather than security and flexibility.
Sure, for some solutions, local first even makes sense, but for the most, not.
How do you make self-hosting appealing to more than weird nerds?
Regular people don't like the Magic Box Which Makes Things Work. They'll begrudgingly shove it in a cupboard and plug it in, but even that is already asking a lot. If it needs any kind of regular maintenance or attention, it is too much effort. "Plug in a harddrive once a month for backups"? You'll have just as much asking them to fly to Mars and yodel the national anthem while doing a cartwheel.
If you think this is only a problem for distributed systems, I have bad news for you.
The reason is simple: control is how you extract rent
They are, as long as you in reach of a base station.
As soon as you travel through a tunnel, hike outside, are on an airplane or are in Australia with latency to U.S or European servers things are different.
Not to mention choice of being offline, either to disable distraction or for reducing roaming costs for some devices while travelling.
I.e., most people don’t care.
Local-first is optimal for creative and productivity apps. (Conversely, non-local-first are terrible for these.)
But most people are neither creative nor optimally productive (or care to be).
it's not that they "don't care", but that they dont know this is an issue that needs to be cared about. Like privacy, they didnt think they need it until they do, but by then it's too late.
The future? I thought all apps were like this before this web2.0 thing ruined it.
'Offline-first' is trying to combine the benefits of both approaches.
Sync problems are harder than just 'use a CRDT'.
What counts as 'consistent' depends on the domain and the exact thing that is being modelled.
In a talk a few years ago [1], Martin Kleppman (one of the authors of the paper that introduced the term "local-first") included this line:
> If it doesn't work if the app developer goes out of business and shuts down the servers, it's not local-first.
That is obviously not something most companies want! If the app works without the company, why are you even paying them? It's much more lucrative to make a company indispensable, where it's very painful to customers if the company goes away (i.e. they stop giving the company money).
[1] https://speakerdeck.com/ept/the-past-present-and-future-of-l...
Anyone uses IMAP email? Works just fine (save for IMAP design but that's another story).
Same with CalDAV.
For stydy I use Anki and it has brilliant sync (it can even automatically/automagaically merge study changes when I study some items on mobile and others on desktop).
Many seem to claim that it's impossible to sync correctly in "colaborative environment" as in it would always involved dozens of people constantly working and editing the document (which would be utterly difficult to track the evolution of)… Most of the time it's not that colaborative and having the data locally makes it easier to work with.
OTOH not everything has to be (web-)app…
In the past it required full sync due to conflict but in the last ~2 years (maybe) I haven't run into such probelm (I guess periodic sync in the background eliminating to much of a backlock probably helps)
When you do serverside stuff you control everything. What users can do, and cannot do.
This lets you both reduce support costs as it is easier to resolve issues even by ad-hoc db query, and more importantly - it lets you retroactively lock more and more useful features behind paywall. This is basically The DRM for your software with extra bonus - you don't even have to compete with previous version of your own software!
i want my local programs back, but without regulatory change it will never happen.
Having built a sync product, it is dramatically simpler (from a technical standpoint) to require that clients are connected, send operations immediately to central location, and then succeed / fail there. Once things like offline sync are part of the picture, there's a whole set of infrequent corner cases that come in that are also very difficult to explain to non-technical people.
These are silly things like: If there's a network error after I sent the last byte to a server, what do I do? You (the client that made the request) don't know if the server actually processed the request. If you're completely reliant on the server for your state, this problem (cough) "doesn't exist", because when the user refreshes, they either see their change or they don't. But, if you have offline sync, you need to either have the server tolerate a duplicate submission, or you need some kind of way for the client to figure out that the server processed the submission.
The bigger issue is naivety. A lot of these corner cases mean that it's unlikely someone can just put together a useful prototype in a weekend or two.
> if it was more profitable we would all be doing it.
More like, if there was more demand we would all be doing it. Most of us have reliable internet connections and don't go out of service often enough to really care about this kind of thing.
Right now, I can throw my phone in the ocean, go to the Apple Store, sign in and my new phone looks and acts like my old phone with all of my data available, my apps and my icons being in the same place.
My wife and I can share calendar events, spreadsheets, photo libraries etc.
That’s not to mention work.
For example, if 2 users are both offline and both buy the same last item in the retailer’s inventory. The race condition has to be solved sometime, and the non-winning user will need a communication from customer service apologizing for overselling the item. Those are pretty frustrating conversations when they come from airlines or hotels.
2. People value convenience over privacy and security
3. Cloud is easy.
It's just easier to implement cloud-first because it's just CRUD with a centralized database on a server. It's still extremely hard to reliably connect two apps directly peer to peer without some centralized server as an intermediary and since you need a centralized server anyway and in addition have to do the peer to peer syncing, "local first with syncing" is inherently more complex than just syncing to a master database. But potential merge conflicts are the same in both.
I can't believe so many replies are struggling with the easy answer: privacy, security, "local first", "open source", "distributed", "open format" etc etc etc are developer goals projected onto a majority cohort of people who have never, and will never, care and yet hold all the potential revenue you need.
Business trumps perfect software engineering almost every time.
I set up a little Pi NAS and have moved all my git repositories there thanks to gitea (I still mirror to github for community interaction) and am gradually migrating everything to be stored locally with encrypted cloud backups.
I've also been working on a local-first, open-source, eventually consistent password manager[0] (using last write wins) for the last 3 years as I can't think of anything more important that we should have control over.
It will be hard for local-first to become more commonplace as SaaS and cloud has become so entrenched but I will keep forging towards a future where we take back ownership of our personal data.
And if it were a file, you could sync it with dropbox or OneDrive.
And if you can do that, they can't make money selling their own cloud service for their local-first app.
More specifically, if you can edit different parts of a same document on different devices, then the document should be split across multiple files that can be synced independently, e.g. a photoshop document where each layer is a separate file and a "main" document simply loads them into a single layer stack.
In fact there are too many document types nowadays that are composites of sub-files and are even actually just a zipped folder under the hood. It feels like we should have just been using files all along, or some sort of file-folder hybrid with OS-level support instead of using zipped folders to contain all the files of a single document.
A more robust idea is to store a log of changes in files that are synced with Dropbox/OneDrive/etc. To prevent conflict warnings from Dropbox, you'll want each device to write to a separate file. Readers re-assemble the logs into (some) canonical total order, then reduce over that to get the document state.
The hard part is re-architecting your app to record all changes, instead of just writing out the current state to disk. However, once you do that, it can form the basis for other features like undo/redo, a view of the file's history, etc.
(The changes don't need to be CRDT/OT messages - anything deterministic works, though it's a good idea to make them "rebase-able", i.e., they will still do something reasonable when replayed on top of a collaborator's concurrent changes.)
How do these services resolve conflicts?
https://www.linkedin.com/pulse/how-obsidians-contrarian-play...
Storing your files on a synced folder (i.e. DropBox or something similar) can handle a lot of heavy lifting.
The use case is not simultaneous editing, folks typically aren’t working on things on different systems at the same time.
Given that as a basis, next, “save early, save often”. The app is “cloud ignorant”. It just sees a local folder. Most of the syncing systems sync up quite quickly, so even if you save it on your desktop and pick up your phone, it’s probably already synced up. “For free”.
Finally your app needs to be cognizant that the file can change behind its back. When it fires up it reloads, or prompts the user, or whatever.
Adding in auto save and versioning like Apple does with their apps, and magic happens (though I honestly don’t know how the Apple apps respond if the saved document is changed underneath it).
There’s a difference between simultaneous and background changes. No reason to over complicate things for the vast majority of use cases.
In fact, many "normal" phone apps are basically just a web-site inside a thin wrapper. So the difference is largely academic in many cases.
It's not giving a "I'm installing an application" vibe, it is giving "I am creating a shortcut to a website" vibes. Apps are installed via the app store, not as weird quasi-bookmarks in your browser.
Now that people are used to having someone in a data center do their backing up and distributing for them, they don't want to that work themselves again, privacy be damned.
You have a disadvantage vs. competitors who focus solely on the latter.
I understand that it's less profitable, which is the real reason nobody does it.
Want 99.99% uptime? Easy.
Cloudflare, AWS, fly.io, Vercel etc. have poured decades of person-years of engineering into platform reliability and operational excellence so you can get it with a few quick CLI commands.
Because FAANG needs your data. Because 5 Eyes needs your data.
Thus, customers get software companies that are SaaS even when they appear to sell some product. Accordingly, most "Computers" sold today are "information-appliances" with constrained predefined use-cases the dominant OS publishers allow people to use.
Few FOSS projects survive contact with such ecosystems, and likewise software App sellers drive platform decay due to shifting priorities that mess with users.
This is also why many modern AAA games have online game-play even when it makes no sense to do so... And why we see 147 fart Apps on the App store. =3
This isn't like choice of fast-food burger where it's slightly harder to drive further to get something a little better; nearly the entire economy of Silicon Valley et al works every day to stop and slow down things like "local first."
...and here we go again. Time is a flat circle.
The pendulum will swing back, I think, for security reasons. "I don't want company X training AI on our data!" (Whatever that means)
"It works everywhere" - Doesn't run on my GPU, OS combination, will tweak settings for a bit.
"Add your API Key here" - Won't do it. "privacy reasons"
"You can run it locally then" - I'm really GPU poor and it runs 5 tok/s.
#1 Reason? - Lots of friction.
It may sound smug but I spent a lot of time trying to understand how to sync things offline. I'm not saying I am incredibly talented, just that I put in the hard work here.
It's very, very obvious to me that a lot of people in the space just aren't willing to do that. To be frank it's obvious in a few of these posts.
So yeah, it takes a bit of effort. If you don't want to genuinely learn some new shit, dig into the papers, be confused - it's probably not for you.
1. In the beginning, there were mainframes and terminals. You saved resources by running apps on a server and connecting to them with cheap terminals
2. Then, PCs happened. You could run reasonably complex programs on them, but communication capabilities were very limited: dialup modem connections or worse
3. Then, internet happened, and remote web apps overtook local apps in many areas (most of those that survived required massive usage of graphics, like games, which is difficult even with modern internet)
4. Then, smartphones happened. At the time of their appearance they didn't have ubiquitous network coverage, so many first apps for these platforms where local. This is eroding too, as communication coverage improves.
So if you look at this, it is clear that main share of computing oscillated back and forth between server and local, moving to local only when communication capabilities do not permit remote running, and once comms catch up, the task of running apps moves back to servers.