End-to-end guide for adding a new synced feature with Electric and TanStack DB. Covers the full journey: design Postgres schema, set REPLICA IDENTITY FULL, define shape, create proxy route, set up TanStack DB collection with electricCollectionOptions, implement optimistic mutations with txid handshake (pg_current_xact_id, awaitTxId), and build live queries with useLiveQuery. Also covers migration from old ElectricSQL (electrify/db pattern does not exist), current API patterns (table as query param not path, handle not shape_id). Load when building a new feature from scratch.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
End-to-end guide for adding a new synced feature with Electric and TanStack DB. Covers the full journey: design Postgres schema, set REPLICA IDENTITY FULL, define shape, create proxy route, set up TanStack DB collection with electricCollectionOptions, implement optimistic mutations with txid handshake (pg_current_xact_id, awaitTxId), and build live queries with useLiveQuery. Also covers migration from old ElectricSQL (electrify/db pattern does not exist), current API patterns (table as query param not path, handle not shape_id). Load when building a new feature from scratch.
This skill builds on electric-shapes, electric-proxy-auth, and electric-schema-shapes. Read those first.
Electric — New Feature End-to-End
Setup
0. Start Electric locally
# docker-compose.ymlservices:postgres:image:postgres:17-alpineenvironment:POSTGRES_DB:electricPOSTGRES_USER:postgresPOSTGRES_PASSWORD:passwordports:-'54321:5432'tmpfs:-/tmpcommand:--c-listen_addresses=*--c-wal_level=logicalelectric:image:electricsql/electric:latestenvironment:DATABASE_URL:postgresql://postgres:password@postgres:5432/electric?sslmode=disableELECTRIC_INSECURE:true# Dev only — use ELECTRIC_SECRET in productionports:-'3000:3000'depends_on:-postgres
docker compose up -d
1. Create Postgres table
CREATE TABLE todos (
id UUID PRIMARY KEY gen_random_uuid(),
user_id UUID ,
text TEXT ,
completed ,
created_at TIMESTAMPTZ now()
);
todos REPLICA ;
DEFAULT
NOT NULL
NOT NULL
BOOLEAN
DEFAULT
false
DEFAULT
ALTER TABLE
IDENTITY
FULL
2. Create proxy route
The proxy forwards Electric protocol params and injects server-side secrets. Use your framework's server route pattern (TanStack Start, Next.js API route, Express, etc.).
If using Drizzle, generate schemas from your table definitions with createSelectSchema(todosTable) from drizzle-zod.
4. Create mutation endpoint
Implement your write endpoint using your framework's server function or API route. The endpoint must return { txid } from the same transaction as the mutation.
// Example: server function that inserts and returns txidasyncfunctioncreateTodo(todo: { text: string; user_id: string }) {
const client = await pool.connect()
try {
await client.query('BEGIN')
const result = await client.query(
'INSERT INTO todos (text, user_id) VALUES ($1, $2) RETURNING id',
[todo.text, todo.user_id]
)
const txResult = await client.query(
'SELECT pg_current_xact_id()::xid::text AS txid'
)
await client.query('COMMIT')
return { id: result.rows[0].id, txid: Number(txResult.rows[0].txid) }
} finally {
client.release()
}
}
HIGH Removing parsers because the TanStack DB schema handles types
Wrong:
// "My Zod schema has z.coerce.date() so I don't need a parser"electricCollectionOptions({
schema: z.object({ created_at: z.coerce.date() }),
shapeOptions: { url: '/api/todos' }, // No parser!
})
Electric's sync path delivers data directly into the collection store, bypassing the TanStack DB schema. The parser in shapeOptions handles type coercion on the sync path; the schema handles the mutation path. You need both. Without the parser, timestamptz arrives as a string and getTime() or other Date methods will fail at runtime.
CRITICAL Using old electrify() bidirectional sync API
Old ElectricSQL (v0.x) had bidirectional SQLite sync. Current Electric is read-only. Writes go through your API endpoint and are reconciled via txid handshake.
See also: electric-orm/SKILL.md — Getting txid from ORM transactions.
See also: electric-proxy-auth/SKILL.md — E2E feature journey includes setting up proxy routes.