Started my practice in local-first this week đ§âđť
It may be still early, there is still much undiscovered complexity, but many great libs are already available, and local-first is sure to be the future đŻ
Here is my initial exploration đ
What is local-first (in practice)
I have been invested in local-first for a while now. First studying the why, then exploring the how. Starting from localfirstconf this June.
Local-first is a new model of building software that spans the full stack, database, backend, frontend.
"Local-first is a set of principles and values, it's not any one technology."
Martin Kleppmann
In practice: data is mainly stored locally and owned by the user. The "server" comes in to sync changes between devices.
This unlocks the world:
- No network requests, the app is local and fast by default
- No network connection required (offline by default)
- Privacy (users own their data)
- Less complexity (no server, no APIs, no backend)
That's why this is inevitable, it's now more about how specifically đ¤
New model, with no clear solutions (yet)
When you own and manage a centralized server the solution to most problems has already been established.
Local-first, new model, new problems, new search for solutions.
Example: I have been experimenting with PGLite.
PGLite: "Run a full Postgres database locally in WASM with reactivity and live sync."
First PGLite local-first example achieved âď¸ @remix_run + PGLite + @vite_js with local database running and working Experimentation in progress đ
You have a local database, you can run any SQL query and such. Great. But what about database init and migrations?
Keep in mind that in local-first clients can have any version of your database. Suppose a user stays offline for 3 years. He kept working on a 3 years old database. When he comes back online, what?
He made 3 years of updates on an old database, adding and removing data models that are not even present in the new database. What do you do?
Somehow you need to execute all the migrations scripts from the user's old database to the new one. Interesting challenge indeed đ¤Ż
Components of a local-first stack
My initial exploration pinpointed 2 core blocks:
- Some way to store and query data locally
- Some way to sync data between devices
That's all. Great, but simple components bring high hidden complexity, as we saw before.
My initial stack at the moment is:
- Local database: PGLite
- Sync data: Electric SQL (next)
I want local data and sync to be separate.
Sync should work the same for any client, but the client can store data locally in any way.
It should be possible to have a single sync service that works for all clients (diagram from Electric SQL's website)
All other technologies will work with these 2 blocks.
Going 𤯠with local first and @EffectTS_ âď¸ Api with the new `HttpApi` âď¸ PGLite local database âď¸ Drizzle for ORM queries âď¸ Client with Remix âď¸ Turborepo setup All in 2 hours (no AI)! The ecosystem is awesome! đŞ
So, how do I get started?
There are already many solutions out there, each proposing a different approach. I suggest taking a look at localfirstweb for a quick overview of the different options.
If you didn't already, check out some talks from localfirstconf as well.
Meanwhile, stay updated with me as I keep exploring this space, as always all practice-oriented and shared open source đŻ
Thinking of writing a full overview of how to use local-first in practice today đ¤ What doubts or questions would you have? What topics would you like covered?
XState course is in full review mode right now. Expect a possible announcement of the release date đ
Meanwhile I have already some projects ready in the pipeline for new content on typeonce.dev.
See you next đ