DEV Community

Thanh Sơn Nguyễn
Thanh Sơn Nguyễn

Posted on

Introducing Postgres Lite: A Pure JS Embedded Engine for Node.js, Bun, and the Browser

🚀 Introducing Postgres Lite: A Pure JS Embedded Engine for Node.js, Bun, and the Browser

PostgreSQL is arguably the most loved database in the world. But when it comes to local-first development, edge computing, or browser-based apps, we usually reach for SQLite.

Why? Because running a full Postgres instance in the browser or as a zero-dependency embedded process in Node/Bun has traditionally been hard—requiring heavy WASM binaries or network proxies.

Today, I'm excited to introduce Postgres Lite (PGLite): An ultra-lightweight, high-performance, in-process PostgreSQL engine built natively for the JavaScript ecosystem.

🛠 What is Postgres Lite?

Postgres Lite is a custom-built SQL engine that implements the PostgreSQL dialect using pure TypeScript/JavaScript. It’s designed to be a robust SQLite alternative that speaks "Postgres," allowing you to use the same schemas, queries, and logic from your backend directly in the frontend or local environments.

  • Zero Emulation: No WASM overhead.
  • Zero Dependency: Just pure JS/TS logic.
  • Universal: Runs in Bun, Node.js, and Modern Browsers (via IndexedDB).

🏗 The Engineering Behind the Performance

Building a database engine from scratch requires more than just parsing SQL. Postgres Lite implements several advanced database engineering techniques to ensure it can handle 1M+ records with ease:

1. Slotted Page Layout

Unlike simple JSON stores, PGLite organizes data into fixed 4KB pages using a slotted-page architecture. This prevents fragmentation and allows for efficient management of variable-length records (like JSONB or TEXT).

2. B-Tree Indexing & O(log n) Lookups

Primary keys and unique constraints are backed by a persistent B-Tree implementation. This ensures that even as your dataset grows to millions of rows, point lookups remain lightning-fast.

3. Write-Ahead Logging (WAL) & ACID Compliance

Data integrity is non-negotiable. PGLite implements WAL. Every mutation is logged to a persistent .wal file before being applied to the main storage. If your process crashes, the engine automatically replays the WAL on the next boot.

4. Volcano Execution Model

PGLite uses an iterator-based processing model. Rows are "pulled" through the execution plan one by one. This means a SELECT * on a million-row table uses a constant and minimal memory footprint instead of loading everything into RAM.

5. LRU Buffer Pool

A sophisticated Least-Recently-Used (LRU) cache manages memory, keeping frequently accessed pages hot and minimizing physical I/O to the disk or IndexedDB.


🚦 Quick Start

Installation

npm install @pglite/core
# or
bun add @pglite/core
Enter fullscreen mode Exit fullscreen mode

Usage in Node.js/Bun

import { PGLite } from "@pglite/core";
import { NodeFSAdapter } from "@pglite/core/node-fs";

const db = new PGLite("app.db", { adapter: new NodeFSAdapter() });

await db.exec(`
  CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    metadata JSONB
  )
`);

await db.exec("INSERT INTO users (name, metadata) VALUES ($1, $2)", 
  ["Alice", { role: "admin" }]
);

const results = await db.query("SELECT * FROM users WHERE name = $1", ["Alice"]);
console.table(results);
Enter fullscreen mode Exit fullscreen mode

Usage in the Browser

import { PGLite } from "@pglite/core";
import { BrowserFSAdapter } from "@pglite/core/browser";

const db = new PGLite("browser_storage", { adapter: new BrowserFSAdapter() });
// Everything else is the same!
Enter fullscreen mode Exit fullscreen mode

⚡️ Supported Features

Despite its "Lite" name, the engine supports a vast subset of Postgres syntax:

  • Complex Joins: INNER, LEFT, LATERAL, and CROSS JOIN.
  • Advanced Querying: CTEs (WITH), UNION, INTERSECT, and Subqueries.
  • Window Functions: ROW_NUMBER(), RANK() via OVER (PARTITION BY...).
  • JSON Power: Full support for JSONB operators (->, ->>, @>, ?).
  • Upserts: ON CONFLICT (col) DO UPDATE SET ...

📊 Performance Benchmark

In our internal tests:

  • Point Lookups (PK): ~0.2ms - 0.5ms.
  • Sequential Scan: 100k rows in < 40ms.
  • Memory Usage: Constant under heavy query load thanks to the Volcano model.

If you are a database enthusiast or a JS developer looking for a better way to handle local data, check out the project on GitHub!

https://github.com/pglite/pglite


Follow me for more deep dives into systems programming with JavaScript!

postgres #javascript #typescript #database #bun #webdev #programming

Top comments (0)