pglite:把 PostgreSQL 塞进浏览器的硬核方案
pglite 将完整的 PostgreSQL 编译为 WebAssembly,在浏览器和 Node.js 中提供真正的 SQL 能力,支持持久化和 pgvector 扩展,重新定义了嵌入式数据库的边界。

作为一个被 Spring Boot、MyBatis 和各种 ORM 折磨多年的 Java 老兵,看到 pglite 这个项目时,我第一反应是:「PostgreSQL 能跑在浏览器里?别闹了,是不是又是个封装 SQLite 的玩具?」
但仔细一看 README,好家伙,这还真不是开玩笑——它把完整的 PostgreSQL 编译成了 WebAssembly(WASM),直接在浏览器、Node.js、Bun、Deno 里跑!而且只有 3MB gzipped,还支持 pgvector 这种热门扩展。作为一个重度数据库用户,我必须说:这玩意儿有点东西。
痛点引入:前端本地存储的“SQL 饥渴症”
传统前端开发中,本地存储要么用 localStorage(弱得可怜),要么上 IndexedDB(API 反人类),或者引入 Dexie.js、PouchDB 等抽象层。但这些方案都绕不开一个痛点:没有真正的 SQL 能力。
你无法写 JOIN,不能用 CTE,更别提 JSONB 操作。每次想做稍微复杂点的数据关联,就得手搓 Map、Set 或者自己维护一套内存索引。这哪是开发,这是自虐。
解决方案:完整的 PostgreSQL 实例,就在你浏览器里
pglite 直接给你一个完整的 PostgreSQL 实例!这意味着你可以用熟悉的 SELECT、JOIN、CTE、甚至 JSONB 操作,完全不用学新语法。更狠的是,它还能持久化到 IndexedDB(浏览器)或文件系统(Node/Bun/Deno),真正做到“本地优先 + 实时响应”。
想象一下:你的 Electron 应用、桌面工具、甚至 PWA,现在都能拥有一个真正的关系型数据库内核,而不用启动后端服务。这不比你手搓一堆 Map 和 Set 香?
核心代码解析:5 行代码搞定 Hello World
安装?一行 npm 就完事:
bash
npm install @electric-sql/pglite
然后直接开干:
javascript
import { PGlite } from "@electric-sql/pglite";
const db = new PGlite();
await db.query("select 'Hello world' as message;");
// -> { rows: [ { message: "Hello world" } ] }
这简洁程度,让我想起了当年第一次用 H2 Database 写单元测试的感觉——轻量、快速、无依赖。
再看持久化配置,设计得相当优雅:
javascript
// 浏览器持久化到 IndexedDB
const db = new PGlite("idb://my-pgdata");
// Node/Bun/Deno 持久化到文件系统
const db = new PGlite("./path/to/pgdata");
注意这里的 URI scheme 设计:idb:// 明确标识了存储后端,既保持了 API 统一,又让开发者一眼看出数据去向。这种细节体现了团队对用户体验的重视。
实战演示:本地向量搜索也能玩?
README 特意提到支持 pgvector——那个做 AI 向量相似度搜索的 PostgreSQL 扩展。也就是说,你可以在浏览器里直接运行 embedding 的 KNN 查询!
虽然目前文档没给具体示例,但理论上你可以这样玩:
javascript
const db = new PGlite();
await db.query(`CREATE EXTENSION IF NOT EXISTS vector;`);
await db.query(`
CREATE TABLE items (
id SERIAL PRIMARY KEY,
embedding VECTOR(384)
);
`);
// 插入向量并查询最近邻...
这为前端 AI 应用打开了新世界:本地向量数据库 + 实时响应,再也不用担心 API 调用延迟或隐私问题。想象一下,在医疗诊断应用中,患者的敏感 embedding 数据完全在本地处理,连网络都不需要。
技术架构深挖:PostgreSQL 的“单用户模式”魔改
PostgreSQL 默认是多进程模型——每个连接 fork 一个新进程。但 WASM 是单线程的,根本不能 fork!那 pglite 怎么做到的?
答案藏在 PostgreSQL 的“单用户模式”(single-user mode)里。这个模式原本用于数据库恢复或初始化,PGlite 团队把它改造成了一个可交互的输入/输出通道,通过 JS 和 WASM 模块通信。
架构流程可以描述为:
- TypeScript API 层接收查询请求
- 通过 Emscripten 的 Module 机制将 SQL 传递给 WASM
- PostgreSQL 单用户模式执行查询
- 结果通过 stdout/stdin 通道返回给 JS
- TypeScript 层解析结果并返回结构化数据
这种设计虽然牺牲了多连接能力(目前只支持单用户),但对于本地嵌入式场景来说,完全够用。毕竟你又不是在搞高并发 Web 服务,而是在写一个桌面笔记应用或者离线数据处理工具。
踩坑指南:Alpha 阶段的现实考量
当然,天下没有免费的午餐:
- Alpha 阶段:项目明确标注 status: alpha,生产环境慎用。
- 单连接限制:不能同时多个 tab 或 worker 访问同一个 DB 实例(IndexedDB 有锁机制,但逻辑上还是单用户)。
- 性能未知:WASM 虽快,但复杂查询 vs 原生 PostgreSQL 肯定有差距,尤其涉及大量 JOIN 或聚合时。
特别要注意的是,虽然支持 pgvector,但在浏览器中执行大规模向量计算可能会阻塞主线程。建议配合 Web Worker 使用,避免 UI 卡顿。
我的真实评价:值得投入的技术方向
如果我是全栈开发者,我会用它来:
- 构建离线优先的 PWA(比如库存管理、问卷收集)
- 在 Electron 应用中替代 SQLite,获得完整 SQL 能力
- 做前端数据原型验证(不用搭后端就能 mock 复杂查询)
至于 Java 后端?短期内用不上,但它的思路值得借鉴——比如未来是否能有 GraalVM Native Image 版的嵌入式 PostgreSQL?
绝对值得深入学习!即使你不写 TS,理解“如何将大型 C 项目(如 PostgreSQL)移植到 WASM”本身就是一项硬核技能。而且,随着边缘计算和本地优先架构兴起,这类嵌入式数据库会越来越重要。
总之,pglite 不是一个玩具,而是一次对“数据库部署边界”的重新定义。它让我想起一句话:最好的数据库,是你根本感觉不到它存在的那个——而现在,它就安静地躺在你的浏览器里,随时待命。