Our friends Johannes Schickling & James Long join us to discuss the movement of local-first, its pros and cons, the tradeoffs, and the path to the warming waters of mostly local apps.
James Long: Yeah, so my current ā Iām kind of like kicking off my own research phase, which⦠I wanted to start it a couple weeks ago, and then kids and life and holidays now. So hopefully, over the holidays Iāll get some time to really dig in here. Iām excited about something⦠And again, this is not mutually exclusive, itās not zero-sum. I fully support the local-first community. I think it is a really, really cool idea, and cool tech, and Iām surprised at how ā itās not mainstream, but Iām surprised at how popular itās become.
At some point I was like āThereās no way people are going to actually really invest in thisā, because itās so much work to build a whole new platform. So really cool to see it. But what I am thinking now is that a lot of the benefits, at least that I was after, I might be able to get them with doing things just more on the edge. And so the way that my thoughts have been sort of evolving is that basically the way Actual worked was it ran your whole SQLite database, and it did the entire backend of the app, backend [unintelligible 01:18:15.02] was in a web worker. So it was a different process, but locally on your machine. So once youāre in the web worker, you can do ā the SQL queries were literally synchronous. They werenāt even async, because itās so faster ā itās so fast that the async overhead of doing multiple promise calls is actually slowing it down. And like just architecturally, it was just like having to ā you introduce an async call somewhere, and then all the call stack has to be async. Itās just super-annoying.
So going back to Johannesā development experience there - itās amazing. Once youāre in that web worker, you async call into it, but then once youāre in there, itās great. But with all of the problems that Iāve been saying - itās hard to integrate services, and this kind of hybrid approach can be mentally taxing. I just kind of want things to work the way everybody else works, which is that you hit a server, and you get something back.
What if we do this ā this multi-tenant approach is really interesting to me. And thereās a company, Turso, turso.tech, which is building out a scalable infrastructure for this, where every single person, every single request even, could possibly get their own SQLite database. So what if basically I took this web worker backend that is local, but itās not actually local, and itās at the closest data center point that could possibly be closest to you? So in that way, Iām still accepting the fact that there is a network call, that there is this boundary there, but itās very close. So Iām hosting currently my website, jlongster.com, on the Northern Virginia data center, or whatever, and Iām in Richmond. So Iām a couple hours drive. And itās about 20 milliseconds overhead.
[01:19:53.02] So I think we can assume 20 to 30 milliseconds overhead for a moderately non-fine-tuned network infrastructure. I think that could even be faster. That to me feels acceptable. And once I accept that single round trip cost, then I can move everything to my server, still have the local SQLite database and have my development experience there, and possibly thereās the SQLite syncing going on in the backend. So Iām not ditching syncing. Youāre probably going to have to sync these changes across a backend distributed network, but itās nice to now own that, because now I can do analytics, I can flip something on in just a minute, without having to get everybody to refresh their clients. I can do a multitude of clients. If I wanted a terminal app for my finances, I could curl something fast and get a boatload of charts. I just get that API, like, instantly. It crosses that network boundary which lets me do everything the way everybody else is kind of doing it.
So the same stuff might be going on, even the syncing, because youāre probably going to have to be syncing that SQLite database⦠Because youāre mutating it locally on that edge instance. Itās going to have to replicate that somehow, elsewhere. But if you draw the line of the app, and local-first is like - at least for the most part - weāre having this hybrid thing where it sort of depends on a server⦠But for the most part, a local-first app in principle is like you draw the line of the entire app and all of the data, and itās all on your computer. And then thereās another circle which is the server, and then itās syncing to this server.
This is like if you draw the line all around your app, but then it reaches over into the server for like one little bit, which is that edge node, and then that edge node is talking to all of the complex server.
And the more I go down this, the more itās like āWell, I really just want to make a single request to the server. I donāt wanna have to go back and forth.ā Maybe Iām evolving to be a āuse the platformā person, and Iām leaning to very light client apps, and now Iām starting to lean into this whole React model where it streams live updates⦠Itās kind of fitting that ā itās taken years to get here, but it seems like React Server Components are actually a thing now. And it is a compelling model. A long time I was like āThis is the weirdest idea everā, especially when I was local-first. I was like āThis doesnāt benefit me at all.ā Now suddenly if Iām flipping my position a little bit, itās like, React Server Components are amazing, because I can run the entire app on the backend, get all of this stuff that I want, and stream in just a couple lightweight components that I want to. I do full navigations maybe, even possibly⦠And the thing that gets me is the ability to flip open new tabs instantly. Thatās one of the things that Iām a little bit like - because things are all local, itās slow to boot up the app. And normally, I was like āWell, you boot up the app once, and youāre digging into your finances for like an hour. I donāt really care.ā But the thing that does feel nice is just to Command+click a link and open up a new window, and use my local macOS windowing system to split the screen, have different tabs, and very quickly, in a very lightweight way just spawn tons of tabs⦠And those tabs load in like 30 milliseconds. That can be hard to do local-first, because youāre buying into this thing where the entire thing must run locally, and so it has to boot up. It has to boot up the thing.
And Johannes, maybe Iām wrong that you can get a 25-millisecond boot-up time on a complex app⦠Iām curious how Overcast feels, if youāve optimized for that. But that is where Iām going to be researching, and kind of diving into. So not to say that this is the solution either, but itās something that Iām very excited about.