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.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
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.