π₯ Stop Wasting Time With REST β Build Real-Time Apps with SQL Over WebSockets!
Let's be honest β REST APIs are starting to feel like fax machines in the age of WhatsApp. We're building rich, collaborative, real-time interfaces, yet still fetching data like it's 1999. It's time to rethink how we design data-driven applications.
In this post, we're diving into a revolutionary approach: using SQL over WebSockets to build blazing-fast, reactive web applications. We'll explore how coupling SQL's expressive querying power with the event-driven nature of WebSockets can elevate your user experience, simplify your backend, and reduce your frontend codebase by a lot.
This technique is real, battle-tested, and achievable today β weβll see how to do it with ElectricSQL and SQLite + CRDTs + WebSockets.
π§ TL;DR β Whatβs the Idea?
- SQL is declarative; you tell it what you want.
- WebSockets are persistent; they give you a channel to push updates.
- CRDTs (conflict-free replicated data types) allow multi-writer sync (even offline!)
- Combine them = pure magic.
Let's look at how you can ship a live collaborative app β like Notion or Figma β without:
- Polling
- Redux spaghetti
- REST endpoints
- Complex backend logic
π Meet ElectricSQL: Real-Time Sync for SQLite
ElectricSQL is a sync layer for SQLite with WebSocket transport, CRDT support, and automatic reactivity. Think Firebase, but SQL-native, offline-first, and open-source (π² yes, really!).
βοΈ Stack Overview
- Backend: PostgreSQL + Electric sync service
- Frontend: SQLite (via WASM) + Electric client
- Sync: WebSockets β bi-directional, instant updates
Under the hood:
- You define your schema declaratively using SQL
- Data updates propagate automatically, no REST required
- The frontend runs a live-replicating SQLite DB (!!)
Let me show you how to build a mini Notion-style collaborative notes app using this magic.
π· Project: Real-Time Collaborative Notes App in 100 Lines of Code
Hereβs a breakdown of a minimal collaborative app.
π§± Step 1 β Setup ElectricSQL
Weβll use the Electric CLI to scaffold a project:
npx create-electric-app realtime-notes
cd realtime-notes
npm install
npm run dev
Boom β youβve got a dev server, sync service, and WebSocket pipeline running.
π Step 2 β Define Your Schema
Inside electric/schema.sql
:
CREATE TABLE IF NOT EXISTS notes (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
);
SELECT crsql_as_crr('notes'); -- enable sync
This makes the notes
table syncable. ElectricSQL will handle all CRDT magic and syncing logic behind the scenes.
π» Step 3 β Use SQLite on the Frontend (in your browser!)
ElectricSQL provides a client that runs SQLite in the browser via WASM.
In your React component:
import { ElectricProvider, useElectricQuery } from 'electric-sql/react';
import { useEffect, useState } from 'react';
function NotesApp() {
const { results, execute, isLoading } = useElectricQuery(
`SELECT * FROM notes ORDER BY updated_at DESC`
);
const [newNote, setNewNote] = useState("");
const addNote = async () => {
const id = crypto.randomUUID();
await execute(
`INSERT INTO notes (id, content) VALUES (?, ?)`,
[id, newNote]
);
setNewNote("");
};
return (
<div>
<input
value={newNote}
onChange={(e) => setNewNote(e.target.value)}
/>
<button onClick={addNote}>Add Note</button>
<ul>
{results.map(note => (
<li key={note.id}>{note.content}</li>
))}
</ul>
</div>
);
}
This is a real SQLite database running in the browser, updated via WebSockets, and the UI reacts automatically. No Redux, no useEffect data fetching dance, no reloading. It's just... reactive.
π‘ Step 4 β Real-Time without REST
Notes are updated in real-time across all clients thanks to the sync protocol and WebSocket connection. Add a note in one tab, it appears instantly on all others.
You didnβt write a single API.
β‘ What Makes This Amazing?
- No API Layer: No Express, no FastAPI, nothing. You query what you need.
- Sync, not Request/Response: Everything is updated via streams.
- Offline-first: Updates propagate when the connection is restored.
- CRDTs built-in: Conflicts auto-resolve via deterministic rules.
- SQL-familiar: Donβt learn a new DSL β this is just SQL.
π§ͺ What Are the Caveats?
Letβs get real β this isnβt magic beans (yet):
- You still need Postgres on the backend for source-of-truth (ElectricSQL syncs to it)
- Debugging sync state might be a learning curve
- CRDT merge logic is automatic, but still worth understanding the model
- Larger datasets? You may need to tweak sync scopes (Γ la GraphQL @live directives)
π§ Who Should Use This?
- π¬ Building chat, docs, boards, collab apps
- π± Need offline support with minimal backend
- π§³ Want SQLite on frontend (cross-platform FTW!)
- π£ Bootstrapping a SaaS without a full API layer
π Further Reading
- ElectricSQL Docs
- Replicache (a similar sync precursor)
- CRDT Explained: by Ink & Switch
- LiveBlocks, Convex, and other real-time stacks
β Conclusion: Ditch REST for Reactive SQL!
Real-time collaboration doesnβt need a RESTful API maze, Redux boilerplate, or multiple database layers. You can:
- Write SQL once
- Sync to frontends in real-time
- Get offline support + conflict resolution
With ElectricSQL and SQL over WebSockets, weβre entering a new era of reactive programming. And itβs much simpler than you think.
So maybe the real question is:
Why are you still writing REST endpoints? π€
Want more tutorials like this? Subscribe and shoot me a comment about the next real-time app you'd like me to build!
π‘ If you need this done β we offer fullstack development services!
Top comments (0)