TL;DR
ElectricSQL syncs your PostgreSQL database to local SQLite in the browser or mobile app — giving you instant reads, offline support, and real-time sync. It's the local-first approach to building reactive apps.
What Is ElectricSQL?
ElectricSQL enables local-first development:
- Sync PostgreSQL to local — data lives on the client
- Instant reads — query local SQLite, no network latency
- Offline support — works without internet
- Real-time sync — changes propagate instantly
- CRDT-based — conflict-free concurrent editing
- React hooks — live queries that auto-update
- Free — Apache 2.0
How It Works
PostgreSQL (source of truth)
↕ Electric sync layer
Local SQLite (in browser/mobile)
↕ Your app reads/writes locally
Quick Start
npm install electric-sql
Define Your Schema
-- In PostgreSQL
CREATE TABLE todos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
completed BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Enable Electric sync
ALTER TABLE todos ENABLE ELECTRIC;
Sync to Client
import { ElectricDatabase } from "electric-sql/browser";
import { electrify } from "electric-sql/wa-sqlite";
import { schema } from "./generated/client";
// Create local SQLite database
const conn = await ElectricDatabase.init("my-app.db");
const electric = await electrify(conn, schema, {
url: "https://your-electric-server.com",
});
// Sync the todos table
await electric.db.todos.sync();
React Integration
import { useLiveQuery } from "electric-sql/react";
import { useElectric } from "./ElectricProvider";
function TodoList() {
const { db } = useElectric();
// Live query — auto-updates when data changes!
const { results: todos } = useLiveQuery(
db.todos.liveMany({
orderBy: { created_at: "desc" },
})
);
const addTodo = async (title: string) => {
// Write locally — syncs to PostgreSQL automatically
await db.todos.create({
data: {
id: crypto.randomUUID(),
title,
completed: false,
},
});
};
const toggleTodo = async (id: string, completed: boolean) => {
await db.todos.update({
where: { id },
data: { completed: !completed },
});
};
return (
<div>
<button onClick={() => addTodo("New task")}>Add Todo</button>
{todos?.map((todo) => (
<div key={todo.id} onClick={() => toggleTodo(todo.id, todo.completed)}>
{todo.completed ? "Done" : "Todo"}: {todo.title}
</div>
))}
</div>
);
}
Filtering Synced Data
// Only sync user's own todos
await electric.db.todos.sync({
where: { user_id: currentUserId },
});
// Sync with related data
await electric.db.projects.sync({
include: {
todos: true,
members: true,
},
});
ElectricSQL vs Alternatives
| Feature | ElectricSQL | Firebase | Supabase Realtime | Convex |
|---|---|---|---|---|
| Local-first | Yes | No | No | No |
| Offline | Full | Limited | No | No |
| Database | PostgreSQL | Firestore | PostgreSQL | Custom |
| Sync model | CRDT | Last-write-wins | Pub/sub | OCC |
| Query locally | SQLite | No | No | No |
| Latency | 0ms (local) | 50-200ms | 50-200ms | 50-200ms |
| Conflict resolution | Automatic | Manual | Manual | Automatic |
Use Cases
- Collaborative apps — Google Docs-style real-time editing
- Offline-first mobile — field work, travel, rural areas
- Instant UIs — zero-latency reads from local database
- Real-time dashboards — data syncs as it changes
- Multi-device sync — seamless cross-device experience
Resources
Building offline-first apps with web data? My Apify tools extract data from any website — sync it locally with ElectricSQL for instant, offline access. Questions? Email spinov001@gmail.com
Top comments (0)