Skillshub electric-orm
install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/electric-sql/electric/electric-orm" ~/.claude/skills/comeonoliver-skillshub-electric-orm && rm -rf "$T"
manifest:
skills/electric-sql/electric/electric-orm/SKILL.mdsource content
This skill builds on electric-shapes and electric-schema-shapes. Read those first.
Electric — ORM Integration
Setup
Drizzle ORM
import { drizzle } from 'drizzle-orm/node-postgres' import { sql } from 'drizzle-orm' import { todos } from './schema' const db = drizzle(pool) // Write with txid for Electric reconciliation async function createTodo(text: string, userId: string) { return await db.transaction(async (tx) => { const [row] = await tx .insert(todos) .values({ id: crypto.randomUUID(), text, userId, }) .returning() const [{ txid }] = await tx.execute<{ txid: string }>( sql`SELECT pg_current_xact_id()::xid::text AS txid` ) return { id: row.id, txid: parseInt(txid) } }) }
Prisma
import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() async function createTodo(text: string, userId: string) { return await prisma.$transaction(async (tx) => { const todo = await tx.todo.create({ data: { id: crypto.randomUUID(), text, userId }, }) const [{ txid }] = await tx.$queryRaw<[{ txid: string }]>` SELECT pg_current_xact_id()::xid::text AS txid ` return { id: todo.id, txid: parseInt(txid) } }) }
Core Patterns
Drizzle migration with REPLICA IDENTITY
// In migration file import { sql } from 'drizzle-orm' export async function up(db) { await db.execute(sql` CREATE TABLE todos ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), text TEXT NOT NULL, completed BOOLEAN DEFAULT false ) `) await db.execute(sql`ALTER TABLE todos REPLICA IDENTITY FULL`) }
Prisma migration with REPLICA IDENTITY
-- prisma/migrations/001_init/migration.sql CREATE TABLE "todos" ( "id" UUID PRIMARY KEY DEFAULT gen_random_uuid(), "text" TEXT NOT NULL, "completed" BOOLEAN DEFAULT false ); ALTER TABLE "todos" REPLICA IDENTITY FULL;
Collection onInsert with ORM
import { createCollection } from '@tanstack/react-db' import { electricCollectionOptions } from '@tanstack/electric-db-collection' export const todoCollection = createCollection( electricCollectionOptions({ id: 'todos', schema: todoSchema, getKey: (row) => row.id, shapeOptions: { url: '/api/todos' }, onInsert: async ({ transaction }) => { const newTodo = transaction.mutations[0].modified const { txid } = await createTodo(newTodo.text, newTodo.userId) return { txid } }, }) )
Common Mistakes
HIGH Not returning txid from ORM write operations
Wrong:
// Drizzle — no txid returned const [todo] = await db.insert(todos).values({ text: 'New' }).returning() return { id: todo.id }
Correct:
// Drizzle — txid in same transaction const result = await db.transaction(async (tx) => { const [row] = await tx.insert(todos).values({ text: 'New' }).returning() const [{ txid }] = await tx.execute<{ txid: string }>( sql`SELECT pg_current_xact_id()::xid::text AS txid` ) return { id: row.id, txid: parseInt(txid) } })
ORMs do not return
pg_current_xact_id() by default. Add a raw SQL query for txid within the same transaction. Without it, optimistic state may drop before the synced version arrives, causing UI flicker.
Source:
AGENTS.md:116-119
MEDIUM Running migrations that drop replica identity
Wrong:
// ORM migration recreates table without REPLICA IDENTITY await db.execute(sql`DROP TABLE todos`) await db.execute(sql`CREATE TABLE todos (...)`) // Missing: ALTER TABLE todos REPLICA IDENTITY FULL
Correct:
await db.execute(sql`DROP TABLE todos`) await db.execute(sql`CREATE TABLE todos (...)`) await db.execute(sql`ALTER TABLE todos REPLICA IDENTITY FULL`)
Some migration tools reset table properties. Always ensure
REPLICA IDENTITY FULL is set after table recreation. Without it, Electric cannot stream updates and deletes correctly.
Source:
website/docs/guides/troubleshooting.md:373
See also: electric-new-feature/SKILL.md — Full write-path journey including txid handshake. See also: electric-schema-shapes/SKILL.md — Schema design affects both shapes and ORM queries.
Version
Targets @electric-sql/client v1.5.10.