π₯ 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.
Let's look at how you can ship a live collaborative app β like Notion or Figma β without:
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!).
Under the hood:
Let me show you how to build a mini Notion-style collaborative notes app using this magic.
Hereβs a breakdown of a minimal collaborative app.
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.
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.
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.
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.
Letβs get real β this isnβt magic beans (yet):
Real-time collaboration doesnβt need a RESTful API maze, Redux boilerplate, or multiple database layers. You can:
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!
Information