Most collection apps make you choose: either your data lives in the cloud and you need internet to use it, or it lives on your device and you lose it when your laptop dies. We didn’t want to make that trade. Orlea is a native desktop app where everything is stored locally in SQLite — instant, offline, yours — and quietly synced to the cloud so it’s always backed up.
This post walks through the stack that makes that work. Not the deep internals, but enough to show the shape of the thing.
The stack at a glance
Orlea runs as a Tauri v2 desktop app — a thin Rust shell wrapping a web view, with a bundled server running inside. That server is built with Hono (a lightweight TypeScript HTTP framework) and talks to a local SQLite database through Drizzle ORM. The frontend is React with TanStack Router and TanStack Query for data fetching, plus Zustand for ephemeral UI state. Styling is Tailwind CSS v4.
The same codebase also deploys to the web as a hosted app. Same API, same UI, same database schema — just a different runtime underneath. On the web, it runs on Vercel. On your Mac, it runs inside Tauri. One codebase, two deployment targets.
Why local-first matters for a collection app
When you paste a link or drop a screenshot into Orlea, it should just be there. No spinner. No “saving…” toast. No failed request because you’re on airplane wifi. That’s the promise of local-first: writes go straight to a database on your machine, and the UI reads from that same database. Network latency is zero because the network isn’t involved.
This matters more than it sounds. Collection is impulsive — you see something, you save it, you move on. Any friction and you don’t bother. A 200ms round trip to a server turns “instant capture” into “wait for it,” and that’s enough to break the habit.
How the database is structured
Orlea uses a per-workspace database model. There are two types of database:
Infra database
One shared database that handles authentication, billing, and the workspace registry. It knows who you are and which workspaces you belong to.
Workspace database
One database per workspace, containing your actual stuff — projects, captures, groups, board layouts. Fully isolated from other workspaces and other users.
On the desktop, these are just SQLite files sitting in a folder on your Mac. On the hosted version, they’re Turso databases — which are also SQLite under the hood, just distributed. Same schema, same queries, same ORM. The only difference is the connection string.
The sync: embedded replicas
Here’s where it gets interesting. When you use Orlea with cloud sync enabled, your local SQLite database becomes an embedded replica of a Turso database. You read and write to the local file normally, and in the background, a sync process pushes your changes to the server and pulls down anything new.
This isn’t a custom sync engine we built from scratch. It’s built into libSQL (the open-source fork of SQLite that Turso maintains). The sync happens at the WAL (write-ahead log) level — individual database frames get shipped back and forth. It’s lightweight, incremental, and handles merge resolution automatically.
The practical effect: you write to SQLite, the UI updates instantly, and a few seconds later those writes appear in the cloud. If someone else made changes (say, you have the web app open on another device), those changes appear in your local database on the next sync cycle. No manual conflict resolution, no “sync failed” modals.
What happens during a sync cycle
A sync scheduler runs in the background on a short interval. Each cycle does roughly this:
- Push — any local writes since the last sync get sent to the server.
- Pull — any remote changes get merged into the local database.
- Diff — a lightweight comparison of table state (row counts, latest timestamps) detects what actually changed, so the UI can update only the affected parts.
- File sync — images and attachments follow separately (more on that below).
If you’re actively typing, the scheduler is smart about it — it debounces pushes so you’re not syncing every keystroke, but also has a force timer so changes don’t sit around too long. If the network drops, it backs off exponentially and picks back up when connectivity returns.
Files are different from data
Database sync handles your text, metadata, and structure. But images, PDFs, and other files travel a different path — they’re uploaded to Cloudflare R2 (S3-compatible object storage) using presigned URLs.
When you add an image to a capture, it’s immediately available locally (it’s already on your disk). In the background, the file gets queued for upload. The queue is persistent — if you quit the app mid-upload, it picks up where it left off next time. Images also get automatic thumbnails generated at multiple sizes, so the board view loads quickly even with hundreds of captures.
Downloads are lazy: files only pull from the cloud when you actually need them. If you open Orlea on a new device, your data structure syncs immediately but images download on demand as you browse.
The Tauri shell
The desktop app itself is Tauri v2 — a Rust framework that wraps a native web view instead of bundling Chromium (like Electron). The result is a ~15MB app that launches fast and uses a fraction of the memory.
Tauri handles the native layer: global keyboard shortcuts (Cmd+Shift+Space for quick capture), file system access, the menu bar, auto-updates, and window management. The Rust backend spawns the Hono server as a child process, waits for it to be ready, and points the web view at it. From the frontend’s perspective, it’s just talking to a localhost API — same as in development.
One codebase, two runtimes
This is the part we’re most proud of. The same TypeScript code runs in both places:
Desktop (Tauri)
Hono API server running locally, SQLite files on disk, native libSQL sync to Turso cloud.
Web (Vercel)
Same Hono API deployed as serverless functions, Turso databases in the cloud, no local files.
The database layer is abstracted through a storage adapter, so the API code doesn’t care whether it’s talking to a local file or a remote Turso instance. Same Drizzle queries, same schema, same validation. Just different connection strings.
Why this approach
We could have gone the easier route: a standard web app with a Postgres database and called it a day. But for a collection app, the tradeoffs don’t work. Collections are personal and spontaneous. They need to feel like they’re on your device — because they are. Opening a tab and waiting for a dashboard to load isn’t the same as hitting a keyboard shortcut and pasting a link in under a second.
Local-first with cloud backup gives you both: the speed and reliability of local software with the safety net of sync. Your data is always accessible, even without internet. And if your laptop disappears tomorrow, everything is recoverable from the cloud.
It’s more work to build this way. But for the kind of tool Orlea is — something you reach for dozens of times a day without thinking — it’s the only approach that felt right.
Try the local-first difference
Orlea is a free macOS app for saving links, notes, and ideas. Instant capture. Offline by default. No account required.