An Elixir library that runs PostgreSQL in-process using PGlite (PostgreSQL compiled to WebAssembly). No external PostgreSQL server required.
- Zero external dependencies - PostgreSQL runs entirely in-process via WebAssembly
- Standard PostgreSQL wire protocol - Works with Postgrex and any PostgreSQL client
- Memory and persistent modes - Choose between ephemeral or persistent storage
- Multiple instances - Run isolated PostgreSQL instances on different ports
- Fast startup - Pre-compiled WASM and PGDATA seeds reduce initialization time by 50-75%
- Full PostgreSQL compatibility - Supports transactions, DDL, DML, JSONB, and complex types
- A Rust binary (
pglite_port) loads PostgreSQL WASM via Wasmtime - PostgreSQL runs in-process and exposes a TCP socket on localhost
- Postgrex connects using the standard PostgreSQL wire protocol
Add to your mix.exs:
def deps do
[{:ex_pglite, "~> 0.1.0"}]
endRequires Rust 1.70+ to build the native binary during mix compile.
# Start PGlite
{:ok, pglite} = Pglite.start_link()
# Connect with Postgrex
{:ok, conn} = Postgrex.start_link(Pglite.get_connection_opts(pglite))
# Run queries
{:ok, result} = Postgrex.query(conn, "SELECT 1", [])| Option | Default | Description |
|---|---|---|
memory |
true |
Use in-memory storage (false for persistent) |
data_dir |
random temp dir | Directory for persistent database files |
tcp_port |
54321 |
TCP port for PostgreSQL connection |
database |
"postgres" |
Database name |
username |
"postgres" |
Username |
password |
"password" |
Password |
startup_timeout |
60000 |
Startup timeout in ms |
pgdata_seed_path |
auto-detected | Pre-initialized PGDATA for faster startup |
The library automatically uses a pre-built PGDATA seed from priv/pgdata_seed.tar.zst when available, reducing startup time by ~50-75%.
Each instance needs a unique TCP port:
{:ok, db1} = Pglite.start_link(tcp_port: 54321)
{:ok, db2} = Pglite.start_link(tcp_port: 54322)defmodule MyTest do
use ExUnit.Case
setup do
{:ok, pglite} = Pglite.start_link()
{:ok, conn} = Postgrex.start_link(Pglite.get_connection_opts(pglite))
on_exit(fn -> GenServer.stop(conn); GenServer.stop(pglite) end)
%{conn: conn}
end
test "queries work", %{conn: conn} do
{:ok, result} = Postgrex.query(conn, "SELECT 1", [])
assert result.rows == [[1]]
end
endgit clone https://github.com/filipecabaco/ex_pglite.git
cd ex_pglite
make build
mix testThe Rust port builds all tools with a single command:
cd pglite_port
cargo build --release
# Create pre-compiled WASM and PGDATA seed (faster startup)
./target/release/build_artifacts ../priv/pglite.wasi ../priv/pglite_prefix ../priv
# Copy binaries to priv
cp target/release/pglite_port target/release/build_artifacts ../priv/bin/This creates:
priv/pglite.cwasm- Pre-compiled native WASM modulepriv/pgdata_seed.tar.zst- Pre-initialized PostgreSQL data directory
- Elixir: 1.14+
- Rust: 1.70+ (for building from source)
- Platforms: macOS (arm64, x86_64), Linux (x86_64)
- Single-process model - Each PGlite instance runs in a single OS process; no multi-process parallelism
- No extensions - PostgreSQL extensions are not supported in the WASM build
- Localhost only - TCP socket binds to 127.0.0.1; not suitable for network-accessible databases
- Performance - Suitable for development, testing, and lightweight workloads; not for production databases
Set PGLITE_DEBUG=1 to enable verbose logging from the Rust runtime:
PGLITE_DEBUG=1 mix testMIT