or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

database-operations.mdextensions.mdfilesystem-storage.mdindex.mdlive-queries.mdsql-templates.mdvector-operations.mdworker-support.md
tile.json

extensions.mddocs/

Extensions

PGlite's pluggable architecture for adding PostgreSQL extensions and custom functionality, supporting both official PostgreSQL contrib modules and custom extensions.

Capabilities

Extension Interface

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>;
}

Extension Configuration

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
  },
});

IVM Extension

Incremental View Maintenance extension for efficient materialized view updates.

/**
 * PostgreSQL Incremental View Maintenance extension
 * Enables efficient updates to materialized views
 */
const pg_ivm: Extension;

Available Contrib Extensions

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 support

Extension Import Pattern

How 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

Types

/** 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:

Using Built-in Extensions

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 views

Using Contrib Extensions

import { 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()");

Creating Custom Extensions

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!"

Extension with Initialization

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"