PGlite is a WASM Postgres build packaged into a TypeScript client library that enables you to run Postgres in the browser, Node.js and Bun, with no need to install any other dependencies.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
PGlite's pluggable architecture for adding PostgreSQL extensions and custom functionality, supporting both official PostgreSQL contrib modules and custom extensions.
Core interface that all extensions must implement.
interface Extension<TNamespace = any> {
/** Unique extension name */
name: string;
/** Extension setup function */
setup: ExtensionSetup<TNamespace>;
}
/**
* Extension setup function
* @param pg - PGlite instance
* @param emscriptenOpts - Emscripten options for modification
* @param clientOnly - Whether running in client-only mode
* @returns Extension setup result
*/
type ExtensionSetup<TNamespace = any> = (
pg: PGliteInterface,
emscriptenOpts: any,
clientOnly?: boolean
) => Promise<ExtensionSetupResult<TNamespace>>;
interface ExtensionSetupResult<TNamespace = any> {
/** Modified emscripten options */
emscriptenOpts?: any;
/** Namespace object to attach to PGlite */
namespaceObj?: TNamespace;
/** Extension bundle URL */
bundlePath?: URL;
/** Post-initialization function */
init?: () => Promise<void>;
/** Cleanup function */
close?: () => Promise<void>;
}How to configure extensions when creating PGlite instances.
interface PGliteOptions<TExtensions = Record<string, Extension>> {
/** Extension map */
extensions?: TExtensions;
// ... other options
}
/**
* Create PGlite with extensions
*/
const db = await PGlite.create({
extensions: {
live,
vector,
// ... other extensions
},
});Incremental View Maintenance extension for efficient materialized view updates.
/**
* PostgreSQL Incremental View Maintenance extension
* Enables efficient updates to materialized views
*/
const pg_ivm: Extension;PostgreSQL contrib extensions available through PGlite.
// Text and string processing
const amcheck: Extension; // Table/index corruption detection
const citext: Extension; // Case-insensitive text type
const fuzzystrmatch: Extension;// Fuzzy string matching functions
const pg_trgm: Extension; // Trigram matching for similarity
// Data types
const cube: Extension; // Multidimensional cube data type
const hstore: Extension; // Key-value pair storage
const isn: Extension; // International Standard Numbers
const ltree: Extension; // Tree-like path data type
const seg: Extension; // Line segment data type
// Indexing
const bloom: Extension; // Bloom filter indexes
const btree_gin: Extension; // B-tree operator classes for GIN
const btree_gist: Extension; // B-tree operator classes for GiST
// Functions and tables
const earthdistance: Extension;// Great circle distance calculations
const tablefunc: Extension; // Functions returning tables
const uuid_ossp: Extension; // UUID generation functions
// Monitoring and logging
const auto_explain: Extension; // Automatic query plan logging
const tcn: Extension; // Triggered change notifications
// Sampling
const tsm_system_rows: Extension; // Row-count tablesample method
const tsm_system_time: Extension; // Time-based tablesample method
// Large objects
const lo: Extension; // Large object supportHow to import and use contrib extensions.
// Import pattern for contrib extensions
import { amcheck } from "@electric-sql/pglite/contrib/amcheck";
import { citext } from "@electric-sql/pglite/contrib/citext";
import { fuzzystrmatch } from "@electric-sql/pglite/contrib/fuzzystrmatch";
import { hstore } from "@electric-sql/pglite/contrib/hstore";
import { ltree } from "@electric-sql/pglite/contrib/ltree";
import { pg_trgm } from "@electric-sql/pglite/contrib/pg_trgm";
import { uuid_ossp } from "@electric-sql/pglite/contrib/uuid-ossp";
// ... and so on for other contrib extensions/** Extension type with namespace */
type ExtensionNamespace<T> = T extends Extension<infer N> ? N : never;
/** Infer extension types from options */
type PGliteWithExtensions<O extends PGliteOptions> =
O extends { extensions: infer E }
? PGliteInterface & {
[K in keyof E]: ExtensionNamespace<E[K]>
}
: PGliteInterface;Usage Examples:
import { PGlite } from "@electric-sql/pglite";
import { live } from "@electric-sql/pglite/live";
import { vector } from "@electric-sql/pglite/vector";
import { pg_ivm } from "@electric-sql/pglite/pg_ivm";
const db = await PGlite.create({
extensions: {
live,
vector,
pg_ivm,
},
});
// Extensions add namespaces to the db object
await db.live.query("SELECT * FROM users");
// db.vector is available for vector operations
// db.pg_ivm is available for incremental viewsimport { PGlite } from "@electric-sql/pglite";
import { hstore } from "@electric-sql/pglite/contrib/hstore";
import { ltree } from "@electric-sql/pglite/contrib/ltree";
import { pg_trgm } from "@electric-sql/pglite/contrib/pg_trgm";
import { uuid_ossp } from "@electric-sql/pglite/contrib/uuid-ossp";
const db = await PGlite.create({
extensions: {
hstore,
ltree,
pg_trgm,
uuid_ossp,
},
});
// Use hstore data type
await db.exec(`
CREATE TABLE products (
id SERIAL PRIMARY KEY,
attributes HSTORE
);
`);
await db.query(
"INSERT INTO products (attributes) VALUES ($1)",
['size => "L", color => "blue"']
);
// Use ltree for hierarchical data
await db.exec(`
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
path LTREE
);
`);
await db.query(
"INSERT INTO categories (path) VALUES ($1)",
["electronics.computers.laptops"]
);
// Use trigram similarity
await db.exec("CREATE EXTENSION IF NOT EXISTS pg_trgm;");
const similar = await db.query(`
SELECT name, similarity(name, $1) as sim
FROM products
WHERE similarity(name, $1) > 0.3
ORDER BY sim DESC
`, ["laptop"]);
// Generate UUIDs
const uuid = await db.query("SELECT uuid_generate_v4()");import { PGlite, Extension } from "@electric-sql/pglite";
// Define custom extension
const myExtension: Extension<{ customFunction: () => string }> = {
name: "my-extension",
setup: async (pg, emscriptenOpts, clientOnly) => {
// Extension setup logic
const customFunction = () => {
return "Hello from custom extension!";
};
return {
namespaceObj: {
customFunction,
},
};
},
};
// Use custom extension
const db = await PGlite.create({
extensions: {
myExtension,
},
});
// Custom namespace is available
console.log(db.myExtension.customFunction()); // "Hello from custom extension!"const complexExtension: Extension<{ helper: (input: string) => Promise<string> }> = {
name: "complex-extension",
setup: async (pg, emscriptenOpts, clientOnly) => {
let initialized = false;
const helper = async (input: string) => {
if (!initialized) {
throw new Error("Extension not initialized");
}
return `processed: ${input}`;
};
return {
namespaceObj: { helper },
init: async () => {
// Perform async initialization
await pg.exec("CREATE TABLE IF NOT EXISTS extension_data (id SERIAL, data TEXT)");
initialized = true;
},
close: async () => {
// Cleanup when database closes
initialized = false;
},
};
},
};
const db = await PGlite.create({
extensions: {
complexExtension,
},
});
// Extension is automatically initialized
const result = await db.complexExtension.helper("test data");
console.log(result); // "processed: test data"Install with Tessl CLI
npx tessl i tessl/npm-electric-sql--pglite