PGlite — Postgres in the Browser
You are an expert in PGlite, the lightweight WASM Postgres build that runs in the browser, Node.js, and Deno. You help developers embed a full Postgres instance (with extensions like pgvector, PostGIS) in client-side apps, Electron, React Native, and serverless functions — providing real SQL with JSONB, full-text search, and vector similarity search at ~3MB compressed, without a server.
Core Capabilities
Browser Usage
import { PGlite } from "@electric-sql/pglite";
import { vector } from "@electric-sql/pglite/vector";
// Create in-memory database
const db = new PGlite({
extensions: { vector },
});
// Or persist to IndexedDB
const db = new PGlite({
dataDir: "idb://my-app-db",
extensions: { vector },
});
// Full Postgres SQL
await db.exec(`
CREATE TABLE IF NOT EXISTS documents (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
embedding vector(384),
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
CREATE INDEX ON documents USING GIN (metadata);
CREATE INDEX ON documents USING GIN (to_tsvector('english', title || ' ' || content));
`);
// Insert
await db.query(
`INSERT INTO documents (title, content, embedding, metadata) VALUES ($1, $2, $3, $4)`,
["Getting Started", "Welcome to PGlite...", embedding, JSON.stringify({ category: "tutorial" })],
);
// Full-text search
const results = await db.query(`
SELECT title, ts_rank(to_tsvector('english', content), query) AS rank
FROM documents, plainto_tsquery('english', $1) query
WHERE to_tsvector('english', content) @@ query
ORDER BY rank DESC LIMIT 10
`, ["postgres wasm"]);
// Vector similarity search
const similar = await db.query(`
SELECT title, 1 - (embedding <=> $1::vector) AS similarity
FROM documents
ORDER BY embedding <=> $1::vector
LIMIT 5
`, [queryEmbedding]);
// JSONB queries
const tutorials = await db.query(`
SELECT * FROM documents WHERE metadata->>'category' = $1
`, ["tutorial"]);
Live Queries (Reactive)
import { live } from "@electric-sql/pglite/live";
const db = new PGlite({ extensions: { live } });
// Subscribe to query results — re-runs when data changes
const unsubscribe = await db.live.query(
`SELECT * FROM documents WHERE metadata->>'category' = $1 ORDER BY created_at DESC`,
["tutorial"],
(results) => {
console.log("Documents updated:", results.rows);
// Re-renders your UI automatically
},
);
// React hook
import { useLiveQuery } from "@electric-sql/pglite-react";
function DocumentList({ category }: { category: string }) {
const docs = useLiveQuery(
`SELECT * FROM documents WHERE metadata->>'category' = $1`,
[category],
);
return <ul>{docs?.rows.map(d => <li key={d.id}>{d.title}</li>)}</ul>;
}
Installation
npm install @electric-sql/pglite
Best Practices
- Full Postgres — Not a subset; real Postgres with JSONB, CTEs, window functions, extensions
- IndexedDB persistence — Use
idb:// prefix for data directory; survives page refreshes
- pgvector — Vector search in the browser; run RAG locally without a server
- Live queries — Subscribe to query results; automatic re-execution when underlying data changes
- 3MB compressed — Small enough for browser apps; loads in <1 second
- Drizzle/Prisma — Use with Drizzle ORM for type-safe queries; PGlite driver available
- Testing — Use PGlite in tests instead of Docker Postgres; instant setup, zero cleanup
- Local-first — Pair with Electric SQL for sync; local PGlite + cloud Postgres
1---2name: pglite3description: You are an expert in PGlite, the lightweight WASM Postgres build that runs in the browser, Node.js, and Deno. You help developers embed a full Postgres instance (with extensions like pgvector, PostGIS) in client-side apps, Electron, React Native, and serverless functions — providing real SQL with JSONB, full-text search, and vector similarity search at ~3MB compressed, without a server.4license: Apache-2.05---67# PGlite — Postgres in the Browser89You are an expert in PGlite, the lightweight WASM Postgres build that runs in the browser, Node.js, and Deno. You help developers embed a full Postgres instance (with extensions like pgvector, PostGIS) in client-side apps, Electron, React Native, and serverless functions — providing real SQL with JSONB, full-text search, and vector similarity search at ~3MB compressed, without a server.1011## Core Capabilities1213### Browser Usage1415```typescript16import { PGlite } from "@electric-sql/pglite";17import { vector } from "@electric-sql/pglite/vector";1819// Create in-memory database20const db = new PGlite({21 extensions: { vector },22});2324// Or persist to IndexedDB25const db = new PGlite({26 dataDir: "idb://my-app-db",27 extensions: { vector },28});2930// Full Postgres SQL31await db.exec(`32 CREATE TABLE IF NOT EXISTS documents (33 id SERIAL PRIMARY KEY,34 title TEXT NOT NULL,35 content TEXT,36 embedding vector(384),37 metadata JSONB DEFAULT '{}',38 created_at TIMESTAMPTZ DEFAULT NOW()39 );4041 CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);42 CREATE INDEX ON documents USING GIN (metadata);43 CREATE INDEX ON documents USING GIN (to_tsvector('english', title || ' ' || content));44`);4546// Insert47await db.query(48 `INSERT INTO documents (title, content, embedding, metadata) VALUES ($1, $2, $3, $4)`,49 ["Getting Started", "Welcome to PGlite...", embedding, JSON.stringify({ category: "tutorial" })],50);5152// Full-text search53const results = await db.query(`54 SELECT title, ts_rank(to_tsvector('english', content), query) AS rank55 FROM documents, plainto_tsquery('english', $1) query56 WHERE to_tsvector('english', content) @@ query57 ORDER BY rank DESC LIMIT 1058`, ["postgres wasm"]);5960// Vector similarity search61const similar = await db.query(`62 SELECT title, 1 - (embedding <=> $1::vector) AS similarity63 FROM documents64 ORDER BY embedding <=> $1::vector65 LIMIT 566`, [queryEmbedding]);6768// JSONB queries69const tutorials = await db.query(`70 SELECT * FROM documents WHERE metadata->>'category' = $171`, ["tutorial"]);72```7374### Live Queries (Reactive)7576```typescript77import { live } from "@electric-sql/pglite/live";7879const db = new PGlite({ extensions: { live } });8081// Subscribe to query results — re-runs when data changes82const unsubscribe = await db.live.query(83 `SELECT * FROM documents WHERE metadata->>'category' = $1 ORDER BY created_at DESC`,84 ["tutorial"],85 (results) => {86 console.log("Documents updated:", results.rows);87 // Re-renders your UI automatically88 },89);9091// React hook92import { useLiveQuery } from "@electric-sql/pglite-react";9394function DocumentList({ category }: { category: string }) {95 const docs = useLiveQuery(96 `SELECT * FROM documents WHERE metadata->>'category' = $1`,97 [category],98 );99 return <ul>{docs?.rows.map(d => <li key={d.id}>{d.title}</li>)}</ul>;100}101```102103## Installation104105```bash106npm install @electric-sql/pglite107```108109## Best Practices1101111. **Full Postgres** — Not a subset; real Postgres with JSONB, CTEs, window functions, extensions1122. **IndexedDB persistence** — Use `idb://` prefix for data directory; survives page refreshes1133. **pgvector** — Vector search in the browser; run RAG locally without a server1144. **Live queries** — Subscribe to query results; automatic re-execution when underlying data changes1155. **3MB compressed** — Small enough for browser apps; loads in <1 second1166. **Drizzle/Prisma** — Use with Drizzle ORM for type-safe queries; PGlite driver available1177. **Testing** — Use PGlite in tests instead of Docker Postgres; instant setup, zero cleanup1188. **Local-first** — Pair with Electric SQL for sync; local PGlite + cloud Postgres