{"id":36949181,"url":"https://github.com/namastexlabs/pgserve","last_synced_at":"2026-05-09T18:01:24.746Z","repository":{"id":325817141,"uuid":"1102260323","full_name":"namastexlabs/pgserve","owner":"namastexlabs","description":"Embedded PostgreSQL 18 server with true concurrent connections - zero config, auto-provision databases","archived":false,"fork":false,"pushed_at":"2026-04-29T22:51:38.000Z","size":1370,"stargazers_count":33,"open_issues_count":4,"forks_count":4,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-30T00:35:49.774Z","etag":null,"topics":["ai-agents","bun","development-tools","embedded-database","multi-tenant","postgres","postgresql","testing"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/pgserve","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/namastexlabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-11-23T05:39:38.000Z","updated_at":"2026-04-29T22:51:42.000Z","dependencies_parsed_at":"2026-04-11T06:03:33.814Z","dependency_job_id":null,"html_url":"https://github.com/namastexlabs/pgserve","commit_stats":null,"previous_names":["namastexlabs/pglite-embedded-server"],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/namastexlabs/pgserve","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/namastexlabs%2Fpgserve","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/namastexlabs%2Fpgserve/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/namastexlabs%2Fpgserve/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/namastexlabs%2Fpgserve/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/namastexlabs","download_url":"https://codeload.github.com/namastexlabs/pgserve/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/namastexlabs%2Fpgserve/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32557843,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T03:21:47.309Z","status":"ssl_error","status_checked_at":"2026-05-03T03:21:43.884Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","bun","development-tools","embedded-database","multi-tenant","postgres","postgresql","testing"],"created_at":"2026-01-13T11:56:01.620Z","updated_at":"2026-05-09T18:01:24.714Z","avatar_url":"https://github.com/namastexlabs.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003epgserve\u003c/h1\u003e\n  \u003cp\u003e\u003cstrong\u003eEmbedded PostgreSQL Server with TRUE Concurrent Connections\u003c/strong\u003e\u003c/p\u003e\n\n  \u003cp\u003e\n    \u003ca href=\"https://www.npmjs.com/package/pgserve\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/pgserve?style=flat-square\u0026color=00D9FF\" alt=\"npm version\"\u003e\u003c/a\u003e\n    \u003cimg src=\"https://img.shields.io/badge/node-%3E%3D18-green?style=flat-square\" alt=\"Node.js\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/PostgreSQL-18-blue?style=flat-square\" alt=\"PostgreSQL\"\u003e\n    \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-green?style=flat-square\" alt=\"License\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://discord.gg/xcW8c7fF3R\"\u003e\u003cimg src=\"https://img.shields.io/discord/1095114867012292758?style=flat-square\u0026color=00D9FF\u0026label=discord\" alt=\"Discord\"\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\n  \u003cp\u003e\u003cem\u003enpx pgserve and it just works, no credentials needed. Zero config, auto-provision databases, unlimited concurrent connections.\u003c/em\u003e\u003c/p\u003e\n\n  \u003cp\u003e\n    \u003ca href=\"#-quick-start\"\u003eQuick Start\u003c/a\u003e •\n    \u003ca href=\"#-features\"\u003eFeatures\u003c/a\u003e •\n    \u003ca href=\"#-cli-reference\"\u003eCLI\u003c/a\u003e •\n    \u003ca href=\"#-api\"\u003eAPI\u003c/a\u003e •\n    \u003ca href=\"#-performance\"\u003ePerformance\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\u003cbr\u003e\n\n## Quick Start\n\n```bash\nnpx pgserve\n```\n\nConnect from any PostgreSQL client — databases auto-create on first connection:\n\n```bash\npsql postgresql://localhost:8432/myapp\n```\n\n\u003e Note: v2 default is the Unix socket — see [Daemon mode](#daemon-mode). The TCP form above is the v1 compat path.\n\n\u003e **Naming.** The npm package stays `pgserve`. The CLI now also ships as\n\u003e `autopg` — both bins route to the same dispatcher. Use `autopg` for the\n\u003e new console (`autopg ui`) and configuration surface (`autopg config`,\n\u003e `autopg restart`); `pgserve \u003csubcommand\u003e` keeps working as a forever\n\u003e alias. Settings live at `~/.autopg/settings.json` and are migrated\n\u003e from `~/.pgserve/` automatically on first run. See\n\u003e [Console](#console-autopg-ui) and [Configuration](#configuration).\n\n\u003cbr\u003e\n\n## Features\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eReal PostgreSQL 18\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eNative binaries, not WASM — full compatibility, extensions support\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eUnlimited Concurrency\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eNative PostgreSQL process forking — no connection locks\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eZero Config\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eJust run \u003ccode\u003epgserve\u003c/code\u003e, connect to any database name\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eAuto-Provision\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eDatabases created automatically on first connection\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eMemory Mode\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eFast and ephemeral for development (default)\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eRAM Mode\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eUse \u003ccode\u003e--ram\u003c/code\u003e for /dev/shm storage (Linux, 2x faster)\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003ePersistent Mode\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eUse \u003ccode\u003e--data ./path\u003c/code\u003e for durable storage\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eAsync Replication\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eSync to real PostgreSQL with minimal overhead\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003epgvector Built-in\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eUse \u003ccode\u003e--pgvector\u003c/code\u003e for auto-enabled vector similarity search\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eCross-Platform\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003eLinux x64, macOS ARM64/x64, Windows x64\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eAny Client Works\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003epsql, node-postgres, Prisma, Drizzle, TypeORM\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003cbr\u003e\n\n## Installation\n\n```bash\n# Canonical install — signed binary from GitHub Releases\ncurl -fsSL https://raw.githubusercontent.com/namastexlabs/pgserve/main/install.sh | bash\n\n# Pinned version\nPGSERVE_VERSION=v2.6.0 curl -fsSL .../install.sh | bash\n```\n\n\u003e `install.sh` fetches the signed tarball from GitHub Releases and verifies it via `gh attestation verify` (Sigstore Rekor public-good). Requires the [`gh` CLI](https://cli.github.com/). pgserve no longer depends on npm — the install + upgrade path is binary tarballs all the way down.\n\n### Windows\n\nDownload `pgserve-windows-x64.exe` from [GitHub Releases](https://github.com/namastexlabs/pgserve/releases).\n\nDouble-click to run, or use CLI:\n\n```cmd\npgserve-windows-x64.exe --port 5432\npgserve-windows-x64.exe --data C:\\pgserve-data\n```\n\n\u003cbr\u003e\n\n## CLI Reference\n\n`autopg` and `pgserve` are interchangeable — every subcommand routes\nthrough the same dispatcher. Use whichever you prefer; new examples in\nthis README and in `console/` use `autopg`.\n\n```\nautopg [options]                       # foreground server (alias: pgserve)\nautopg daemon                          # long-lived background daemon\nautopg install [--port N] [--data P]   # register pgserve under pm2\nautopg uninstall                       # remove from pm2 (data dir kept)\nautopg status                          # pm2 + on-disk config snapshot\nautopg url | autopg port               # canonical connection string / port\nautopg config \u003clist|get|set|edit|path|init\u003e   # manage ~/.autopg/settings.json\nautopg restart                         # pm2-aware: pm2 restart pgserve, else SIGTERM+respawn\nautopg ui [--port N] [--no-open]       # local web console on 127.0.0.1\n```\n\nForeground options accepted by `autopg` / `pgserve` (no subcommand):\n\n```\nOptions:\n  --port \u003cnumber\u003e       PostgreSQL port (default: 8432)\n  --data \u003cpath\u003e         Data directory for persistence (default: in-memory)\n  --ram                 Use RAM storage via /dev/shm (Linux only, fastest)\n  --host \u003chost\u003e         Host to bind to (default: 127.0.0.1)\n  --log \u003clevel\u003e         Log level: error, warn, info, debug (default: info)\n  --cluster             Force cluster mode (auto-enabled on multi-core)\n  --no-cluster          Force single-process mode\n  --workers \u003cn\u003e         Number of worker processes (default: CPU cores)\n  --no-provision        Disable auto-provisioning of databases\n  --sync-to \u003curl\u003e       Sync to real PostgreSQL (async replication)\n  --sync-databases \u003cp\u003e  Database patterns to sync (comma-separated)\n  --pgvector            Auto-enable pgvector extension on new databases\n  --max-connections \u003cn\u003e Max concurrent connections (default: 1000)\n  --help                Show help message\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eExamples\u003c/b\u003e\u003c/summary\u003e\n\n```bash\n# Development (memory mode, auto-clusters on multi-core)\npgserve\n\n# RAM mode (Linux only, 2x faster)\npgserve --ram\n\n# Persistent storage\npgserve --data /var/lib/pgserve\n\n# Custom port\npgserve --port 5433\n\n# Enable pgvector for AI/RAG applications\npgserve --pgvector\n\n# RAM mode + pgvector (fastest for AI workloads)\npgserve --ram --pgvector\n\n# Sync to production PostgreSQL\npgserve --sync-to \"postgresql://user:pass@db.example.com:5432/prod\"\n```\n\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n## Daemon mode\n\n`pgserve@2` ships a singleton daemon that binds a Unix control socket\ninside `$XDG_RUNTIME_DIR/pgserve` (fallback `/tmp/pgserve`). One daemon\nper host serves every consumer on the box — no port conflicts, no\ncredentials, kernel-rooted identity. Run it under PM2 or systemd so it\nrestarts automatically.\n\n```bash\n# Foreground (for debugging)\npgserve daemon\n\n# Stop a running daemon\npgserve daemon stop\n```\n\nA second `pgserve daemon` invocation while the first is running exits with\n`already running, pid N`. A daemon killed with `kill -9` leaves an orphan\nPID file + socket; the next `pgserve daemon` boot detects the dead pid and\ncleans both up automatically.\n\nConnect from any libpq client (no host/port/user/password required —\nthe daemon authenticates via SO_PEERCRED on accept):\n\n```bash\npsql -h \"${XDG_RUNTIME_DIR:-/tmp}/pgserve\" -d myapp\n# or via connection URI\npsql \"postgresql:///myapp?host=${XDG_RUNTIME_DIR:-/tmp}/pgserve\"\n```\n\n### Supervised by PM2 — `pgserve install` (recommended)\n\n`pgserve install` registers pgserve as a hardened pm2 process in one\ncommand. Idempotent: re-running it is a no-op when already installed.\n\n```bash\npgserve install                    # one-shot register + start under pm2\npgserve install --port 8442        # custom port\npgserve install --data /data/pg    # custom data dir\n\npgserve url                        # postgres://localhost:8432/postgres\npgserve port                       # 8432\npgserve status                     # pm2 + on-disk config snapshot\npgserve uninstall                  # remove from pm2; keep data dir\n```\n\n**Hardened defaults** (tuned for production-grade Postgres workloads,\nnot toy-machine values):\n\n| Flag | Default | Why |\n|------|---------|-----|\n| `--max-memory-restart` | `4G` | Postgres realistic working set: shared_buffers + autovacuum + connection backends. 1G OOM-kills under modest load. Override with `PGSERVE_MAX_MEMORY=8G pgserve install`. |\n| `--max-restarts` | `50` | Tolerates extended outages (NATS reconnect storms, host pressure). Combined with `--min-uptime`, only RAPID failures count. |\n| `--min-uptime` | `10000` ms | Restart counts against the cap only when the process crashed within 10s of starting. Healthy long-uptime crashes don't burn the budget. |\n| `--restart-delay` | `4000` ms | Initial gap between restarts. |\n| `--exp-backoff-restart-delay` | `100` → ~60000 ms | Exponential spread on repeated failures so we don't hammer pm2 + the host on persistent issues. |\n| `--kill-timeout` | `60000` ms | Postgres needs time to flush WAL on graceful shutdown; 60s headroom. |\n| `--log-date-format` | `YYYY-MM-DD HH:mm:ss.SSS` | Operator-friendly timestamps in pm2 logs. |\n| `--output` / `--error` | `~/.pgserve/logs/pgserve-{out,error}.log` | Rotates via pm2-logrotate (install separately). |\n\nConfig: `~/.pgserve/config.json` (override the directory with\n`PGSERVE_CONFIG_DIR`). Memory ceiling: env-tunable via\n`PGSERVE_MAX_MEMORY` at install time.\n\nDownstream services that need a Postgres connection can shell out to\n`pgserve install` (no-op if already running) and read the canonical URL\nfrom `pgserve url` instead of spinning up their own embedded pgserve.\n\n#### Manual ecosystem.config.cjs (legacy)\n\n```javascript\nmodule.exports = {\n  apps: [{\n    name: 'pgserve',\n    script: 'pgserve',\n    args: 'daemon',\n    autorestart: true,\n    max_memory_restart: '1G',\n    env: { XDG_RUNTIME_DIR: '/run/user/1000' },\n  }],\n};\n```\n\n```bash\npm2 start ecosystem.config.cjs \u0026\u0026 pm2 save\n```\n\n### Supervised by systemd\n\n`/etc/systemd/user/pgserve.service`:\n\n```ini\n[Unit]\nDescription=pgserve daemon\nAfter=default.target\n\n[Service]\nType=simple\nExecStart=/usr/bin/env npx pgserve daemon\nRestart=on-failure\nRestartSec=5\n\n[Install]\nWantedBy=default.target\n```\n\nEnable for the current user:\n\n```bash\nsystemctl --user enable --now pgserve\njournalctl --user -u pgserve -f\n```\n\nThe systemd user unit inherits `XDG_RUNTIME_DIR` automatically; the daemon\nbinds `${XDG_RUNTIME_DIR}/pgserve/control.sock` (mode 0600, dir mode 0700)\nplus a `.s.PGSQL.5432` symlink so off-the-shelf PostgreSQL clients connect\nwithout further configuration.\n\n\u003cbr\u003e\n\n## Fingerprint isolation\n\nEach consumer is identified by a **kernel-rooted fingerprint** derived from\nthe peer's `SO_PEERCRED` plus the resolved `package.json` `name`, collapsed\nto 12 hex chars. The daemon auto-creates one database per fingerprint —\n`app_\u003csanitized-name\u003e_\u003c12hex\u003e` — and refuses to route a peer into any other\ndatabase with SQLSTATE `28P01 invalid_authorization — database fingerprint\nmismatch`.\n\n```bash\n# What `psql -l` shows on a host with three consumers:\n$ psql -h \"${XDG_RUNTIME_DIR:-/tmp}/pgserve\" -l\n        Name           |  Owner   | ...\n-----------------------+----------+----\n app_genie_a1b2c3d4e5f6 | postgres | ...\n app_brain_4f3e2d1c0b9a | postgres | ...\n app_omni_9876543210ab  | postgres | ...\n```\n\n**Monorepo rule:** the **root** `package.json` `name` wins. Every workspace\nunder it shares one fingerprint and one database — sub-packages do **not**\nget their own. If you need separate isolation, run them from separate\ncheckouts.\n\n**Sanitization:** non-`[a-z0-9]` runs collapse to `_`, lowercased, truncated\nto 30 chars so the final DB name stays within PostgreSQL's 63-char limit.\nA name like `@scope/foo bar` becomes `_scope_foo_bar`.\n\n**Emergency kill switch:** `PGSERVE_DISABLE_FINGERPRINT_ENFORCEMENT=1`\ndisables enforcement for the daemon process. Use it as a debugging tool\nonly — every bypassed connection emits an `enforcement_kill_switch_used`\naudit event and the daemon logs a deprecation warning at boot.\n\n\u003cbr\u003e\n\n## Long-running apps: `pgserve.persist`\n\nDefault lifecycle is **ephemeral**: a database whose `liveness_pid` is dead\nAND whose `last_connection_at` is older than 24h is dropped on the next GC\nsweep (boot, hourly, sampled on-connect). Reaped DBs emit\n`db_reaped_ttl` or `db_reaped_liveness` audit events.\n\nIf your app holds state worth keeping past 24h of idle — genie's wish/agent\nstore, internal dashboards, anything you'd be unhappy to lose — declare\npersistence in `package.json`:\n\n```jsonc\n{\n  \"name\": \"my-long-lived-app\",\n  \"pgserve\": { \"persist\": true }\n}\n```\n\nPersisted databases are **never** reaped, regardless of liveness or TTL.\nDev workloads with long debug cycles do not normally need this — any new\nconnection slides the TTL window forward. Reach for `pgserve.persist` when\nthe app is genuinely long-lived (production daemon, dashboard, durable\nagent state), not just for convenience.\n\n\u003cbr\u003e\n\n## Console (`autopg ui`)\n\nA local web console for inspecting and editing the running cluster.\nRuns in-process via `node:http`, binds 127.0.0.1 only, single-user dev\ntool — no auth, no TLS, never expose it.\n\n```bash\nautopg ui                  # walk 8433–8533 picking the first free port\nautopg ui --port 8500      # bind exactly 8500\nautopg ui --no-open        # skip browser launch (CI / headless)\n```\n\nThe first stateful screen — **Settings** — is functional today: it\nrenders the 6-section schema (server / runtime / sync / supervision /\npostgres / ui), validates inline, and round-trips through\n`~/.autopg/settings.json` with optimistic concurrency (sha256 etag +\n`If-Match`). The other 10 screens (Databases, Tables, SQL, Optimizer,\nSecurity, Ingress, Health, Sync, RLM-trace, RLM-sim) are scaffolded\nas `[ coming soon ]` placeholders — Health ships next.\n\nThe UI shells out to the CLI for every mutation (`autopg config set`\nunder PUT, `autopg restart` under POST). The daemon stays untouched\n— no HTTP API, no signal-based reload — so the console works even\nwhen no daemon is running.\n\nSee [`console/README.md`](./console/README.md) for the local dev loop\nand design-system source.\n\n\u003cbr\u003e\n\n## Configuration\n\nThe CLI is the source of truth. Settings live at\n`~/.autopg/settings.json` (override the directory with\n`AUTOPG_CONFIG_DIR`; the legacy `PGSERVE_CONFIG_DIR` is still honored\nand falls back to `~/.pgserve/`). Every write is atomic, chmod 0600,\nand tagged with a sha256 etag for optimistic concurrency on the UI\nhelper's PUT path.\n\nSchema sections (one per `~/.autopg/settings.json` top-level key):\n\n| Section | Purpose |\n|---------|---------|\n| `server` | Router port/host, backend socket, superuser credentials |\n| `runtime` | Log level, auto-provision, pgvector, data dir |\n| `sync` | WAL-based logical replication toggle |\n| `supervision` | pm2 hardening defaults (memory, restart, kill timeout) |\n| `postgres` | 15 curated GUCs (`shared_buffers`, `wal_level`, …) + `_extra` raw passthrough |\n| `ui` | Console theme / phosphor / density / CRT toggle |\n\n```bash\nautopg config init                              # write defaults\nautopg config list                              # KEY VALUE SOURCE table\nautopg config get postgres.shared_buffers       # machine-friendly value\nautopg config set postgres.shared_buffers 256MB # validates + atomic write\nautopg config edit                              # opens $EDITOR on settings.json\nautopg config path                              # absolute path (honors AUTOPG_CONFIG_DIR)\n```\n\n**Precedence:** `default \u003c file \u003c env`. `AUTOPG_*` env vars beat\n`PGSERVE_*` (the legacy form is still honored with a one-time\ndeprecation log per process, so existing operators keep working).\nThe console shows a yellow `OVERRIDDEN BY ENV` chip on rows whose\nenv var is currently set.\n\n**GUC passthrough:** `postgres._extra` is a free-form `{ gucName: scalar }`\nmap for any PostgreSQL setting outside the curated 15. Names must match\n`^[a-z][a-z0-9_]*$`; values must be string / number / boolean (no\nnewlines, no leading `-`). Both layers are revalidated at boot, so a\ntypo logs a `logger.warn` and is dropped — postgres still starts.\n\n**One-shot migration:** on first run, if `~/.pgserve/` exists and\n`~/.autopg/` does not, the contents are copied (preserving mtimes)\nand a `MIGRATED-FROM-PGSERVE.md` marker is dropped in the old dir.\nIdempotent — second run is a no-op.\n\nFull schema reference: [`docs/settings-schema.md`](./docs/settings-schema.md).\n\n\u003cbr\u003e\n\n## Compat TCP via `--listen`\n\nTCP is **off by default** in v2. Bring it back only when you need it\n(Kubernetes pods, remote sync, legacy clients that cannot speak Unix\nsockets) by opting in:\n\n```bash\npgserve daemon --listen :5432\n# Repeatable for multiple binds:\npgserve daemon --listen :5432 --listen 0.0.0.0:5433\n```\n\nTCP peers cannot use `SO_PEERCRED`, so they **must** authenticate at\nconnect time. Issue a bearer token bound to a known fingerprint:\n\n```bash\n# Prints the token ONCE; the daemon stores only its hash.\npgserve daemon issue-token --fingerprint a1b2c3d4e5f6\n\n# TCP client passes it via libpq application_name:\n#   ?fingerprint=a1b2c3d4e5f6\u0026token=\u003cbearer\u003e\n\n# Revoke when done:\npgserve daemon revoke-token \u003ctoken-id\u003e\n```\n\nAudit events: `tcp_token_issued`, `tcp_token_used`, `tcp_token_denied`.\nTokens are verified with constant-time compare. Without a valid token a\nTCP connection is refused — there is no anonymous TCP path.\n\nVerify no port is bound when `--listen` is **not** set:\n\n```bash\nss -tlnp | grep pgserve   # no rows expected\n```\n\n\u003cbr\u003e\n\n## API\n\nDaemon-first apps can let the first caller install/start the singleton and\nthen connect through the Unix socket. The daemon derives the app identity\nfrom kernel peer credentials and routes it to that app's signed fingerprint\ndatabase.\n\n```javascript\nimport { daemonClientOptions, ensureDaemon } from 'pgserve';\nimport postgres from 'postgres';\n\nawait ensureDaemon({\n  dataDir: `${process.env.HOME}/.pgserve/data`,\n  logLevel: 'warn',\n});\n\nconst sql = postgres(daemonClientOptions());\nawait sql`SELECT current_database()`;\n```\n\nThe classic TCP router API remains available for explicit v1-compatible\nembedded servers:\n\n```javascript\nimport { startMultiTenantServer } from 'pgserve';\n\nconst server = await startMultiTenantServer({\n  port: 8432,\n  host: '127.0.0.1',\n  baseDir: null,        // null = memory mode\n  logLevel: 'info',\n  autoProvision: true,\n  enablePgvector: true, // Auto-enable pgvector on new databases\n  syncTo: null,         // Optional: PostgreSQL URL for replication\n  syncDatabases: null   // Optional: patterns like \"myapp,tenant_*\"\n});\n\n// Get stats\nconsole.log(server.getStats());\n\n// Graceful shutdown\nawait server.stop();\n```\n\n\u003cbr\u003e\n\n## Framework Integration\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003enode-postgres\u003c/b\u003e\u003c/summary\u003e\n\n```javascript\nimport pg from 'pg';\n\nconst client = new pg.Client({\n  connectionString: 'postgresql://localhost:8432/myapp'\n});\n\nawait client.connect();\nawait client.query('CREATE TABLE users (id SERIAL, name TEXT)');\nawait client.query(\"INSERT INTO users (name) VALUES ('Alice')\");\nconst result = await client.query('SELECT * FROM users');\nconsole.log(result.rows);\nawait client.end();\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003ePrisma\u003c/b\u003e\u003c/summary\u003e\n\n```prisma\n// prisma/schema.prisma\ndatasource db {\n  provider = \"postgresql\"\n  url      = env(\"DATABASE_URL\")\n}\n```\n\n```bash\n# .env\nDATABASE_URL=\"postgresql://localhost:8432/myapp\"\n\n# Run migrations\nnpx prisma migrate dev\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eDrizzle\u003c/b\u003e\u003c/summary\u003e\n\n```typescript\nimport { drizzle } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';\n\nconst pool = new Pool({\n  connectionString: 'postgresql://localhost:8432/myapp'\n});\n\nconst db = drizzle(pool);\nconst users = await db.select().from(usersTable);\n```\n\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n## Async Replication\n\nSync ephemeral pgserve data to a real PostgreSQL database. Uses native logical replication for **zero performance impact** on the hot path.\n\n```bash\n# Sync all databases\npgserve --sync-to \"postgresql://user:pass@db.example.com:5432/mydb\"\n\n# Sync specific databases (supports wildcards)\npgserve --sync-to \"postgresql://...\" --sync-databases \"myapp,tenant_*\"\n```\n\n\u003e Replication is handled by PostgreSQL's WAL writer process, completely off the runtime event loop. Sync failures don't affect main server operation.\n\n\u003cbr\u003e\n\n## pgvector (Vector Search)\n\npgvector is **built-in** — no separate installation required. Just enable it:\n\n```bash\n# Auto-enable pgvector on all new databases\npgserve --pgvector\n\n# Combined with RAM mode for fastest vector operations\npgserve --ram --pgvector\n```\n\nWhen `--pgvector` is enabled, every new database automatically has the vector extension installed. No SQL setup required.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eUsing pgvector\u003c/b\u003e\u003c/summary\u003e\n\n```sql\n-- Create table with vector column (1536 = OpenAI embedding size)\nCREATE TABLE documents (id SERIAL, content TEXT, embedding vector(1536));\n\n-- Insert with embedding\nINSERT INTO documents (content, embedding) VALUES ('Hello', '[0.1, 0.2, ...]');\n\n-- k-NN similarity search (L2 distance)\nSELECT content FROM documents ORDER BY embedding \u003c-\u003e $1 LIMIT 10;\n```\n\nSee [pgvector documentation](https://github.com/pgvector/pgvector) for full API reference.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eWithout --pgvector flag\u003c/b\u003e\u003c/summary\u003e\n\nIf you don't use `--pgvector`, you can still enable pgvector manually per database:\n\n```sql\nCREATE EXTENSION IF NOT EXISTS vector;\n```\n\n\u003c/details\u003e\n\n\u003e pgvector 0.8.1 is bundled with the PostgreSQL binaries. Supports L2 distance (`\u003c-\u003e`), inner product (`\u003c#\u003e`), and cosine distance (`\u003c=\u003e`).\n\n\u003cbr\u003e\n\n## Performance\n\n### CRUD Benchmarks\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eScenario\u003c/th\u003e\n    \u003cth\u003eSQLite\u003c/th\u003e\n    \u003cth\u003ePostgreSQL\u003c/th\u003e\n    \u003cth\u003epgserve 1.2.0\u003c/th\u003e\n    \u003cth\u003epgserve v2\u003c/th\u003e\n    \u003cth\u003epgserve v2 --ram\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eConcurrent Writes\u003c/b\u003e (10 agents)\u003c/td\u003e\n    \u003ctd\u003e91 qps\u003c/td\u003e\n    \u003ctd\u003e204 qps\u003c/td\u003e\n    \u003ctd\u003e1,667 qps\u003c/td\u003e\n    \u003ctd\u003e2,273 qps\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e4,167 qps\u003c/b\u003e 🏆\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eMixed Workload\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003e383 qps\u003c/td\u003e\n    \u003ctd\u003e484 qps\u003c/td\u003e\n    \u003ctd\u003e507 qps\u003c/td\u003e\n    \u003ctd\u003e1,133 qps\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e2,109 qps\u003c/b\u003e 🏆\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eWrite Lock\u003c/b\u003e (50 writers)\u003c/td\u003e\n    \u003ctd\u003e111 qps\u003c/td\u003e\n    \u003ctd\u003e228 qps\u003c/td\u003e\n    \u003ctd\u003e2,857 qps\u003c/td\u003e\n    \u003ctd\u003e3,030 qps\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e4,348 qps\u003c/b\u003e 🏆\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n### Vector Benchmarks (pgvector)\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eMetric\u003c/th\u003e\n    \u003cth\u003ePostgreSQL\u003c/th\u003e\n    \u003cth\u003epgserve 1.2.0\u003c/th\u003e\n    \u003cth\u003epgserve v2\u003c/th\u003e\n    \u003cth\u003epgserve v2 --ram\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eVector INSERT\u003c/b\u003e (1000 × 1536-dim)\u003c/td\u003e\n    \u003ctd\u003e152/sec\u003c/td\u003e\n    \u003ctd\u003e392/sec\u003c/td\u003e\n    \u003ctd\u003e387/sec\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e1,082/sec\u003c/b\u003e 🏆\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003ek-NN Search\u003c/b\u003e (k=10, 10k corpus)\u003c/td\u003e\n    \u003ctd\u003e22 qps\u003c/td\u003e\n    \u003ctd\u003e33 qps\u003c/td\u003e\n    \u003ctd\u003e31 qps\u003c/td\u003e\n    \u003ctd\u003e30 qps\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003eRecall@10\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003e100%\u003c/td\u003e\n    \u003ctd\u003e100%\u003c/td\u003e\n    \u003ctd\u003e100%\u003c/td\u003e\n    \u003ctd\u003e100%\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003e \u003cb\u003eWhy pgserve wins on writes:\u003c/b\u003e RAM mode uses \u003ccode\u003e/dev/shm\u003c/code\u003e (tmpfs), eliminating fsync latency. Vector search is CPU-bound, so RAM mode shows minimal benefit there.\n\n### Final Score\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eEngine\u003c/th\u003e\n    \u003cth\u003eCRUD QPS\u003c/th\u003e\n    \u003cth\u003eVec QPS\u003c/th\u003e\n    \u003cth\u003eRecall\u003c/th\u003e\n    \u003cth\u003eP50\u003c/th\u003e\n    \u003cth\u003eP99\u003c/th\u003e\n    \u003cth\u003eScore\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003eSQLite\u003c/td\u003e\n    \u003ctd\u003e195\u003c/td\u003e\n    \u003ctd\u003eN/A\u003c/td\u003e\n    \u003ctd\u003eN/A\u003c/td\u003e\n    \u003ctd\u003e6.3ms\u003c/td\u003e\n    \u003ctd\u003e17.3ms\u003c/td\u003e\n    \u003ctd\u003e117\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003epgserve 1.2.0\u003c/td\u003e\n    \u003ctd\u003e305\u003c/td\u003e\n    \u003ctd\u003e65\u003c/td\u003e\n    \u003ctd\u003e100%\u003c/td\u003e\n    \u003ctd\u003e3.3ms\u003c/td\u003e\n    \u003ctd\u003e7.0ms\u003c/td\u003e\n    \u003ctd\u003e209\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003ePostgreSQL\u003c/td\u003e\n    \u003ctd\u003e1,677\u003c/td\u003e\n    \u003ctd\u003e152\u003c/td\u003e\n    \u003ctd\u003e100%\u003c/td\u003e\n    \u003ctd\u003e6.0ms\u003c/td\u003e\n    \u003ctd\u003e19.0ms\u003c/td\u003e\n    \u003ctd\u003e1,067\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003epgserve v2\u003c/td\u003e\n    \u003ctd\u003e2,145\u003c/td\u003e\n    \u003ctd\u003e149\u003c/td\u003e\n    \u003ctd\u003e100%\u003c/td\u003e\n    \u003ctd\u003e5.3ms\u003c/td\u003e\n    \u003ctd\u003e13.0ms\u003c/td\u003e\n    \u003ctd\u003e1,347\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cb\u003epgserve v2 --ram\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e3,541\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e381\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e100%\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e3.3ms\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e10.7ms\u003c/b\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003e2,277\u003c/b\u003e 🏆\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003e \u003cb\u003eMethodology:\u003c/b\u003e Recall@k measured against brute-force ground truth (industry standard). PostgreSQL baseline is Docker \u003ccode\u003epgvector/pgvector:pg18\u003c/code\u003e. RAM mode available on Linux and WSL2.\n\u003e\n\u003e Run benchmarks yourself: \u003ccode\u003ebun tests/benchmarks/runner.js --include-vector\u003c/code\u003e\n\n\u003cbr\u003e\n\n## Use Cases\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003ch4\u003eDevelopment \u0026 Testing\u003c/h4\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003cb\u003eLocal Development\u003c/b\u003e — PostgreSQL without Docker\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eIntegration Testing\u003c/b\u003e — Real PostgreSQL, not mocks\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eCI/CD Pipelines\u003c/b\u003e — Fresh databases per test run\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eE2E Testing\u003c/b\u003e — Isolated database for Playwright/Cypress\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003ch4\u003eAI \u0026 Agents\u003c/h4\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003cb\u003eAI Agent Memory\u003c/b\u003e — Isolated, concurrent-safe database\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eLLM Tool Use\u003c/b\u003e — Give AI models a real PostgreSQL\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eRAG Applications\u003c/b\u003e — Store embeddings with pgvector\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003ch4\u003eMulti-Tenant \u0026 SaaS\u003c/h4\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003cb\u003eTenant Isolation\u003c/b\u003e — Auto-provision per tenant\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eDemo Environments\u003c/b\u003e — Instant sandboxed PostgreSQL\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eMicroservices Dev\u003c/b\u003e — Each service gets its own DB\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"50%\"\u003e\n      \u003ch4\u003eEdge \u0026 Embedded\u003c/h4\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003cb\u003eIoT Devices\u003c/b\u003e — Full PostgreSQL on Raspberry Pi\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eDesktop Apps\u003c/b\u003e — Electron with embedded PostgreSQL\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eOffline-First\u003c/b\u003e — Local DB that syncs when online\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003cbr\u003e\n\n## Requirements\n\n- **Runtime**: Node.js \u003e= 18 (npm/npx)\n- **Platform**: Linux x64, macOS ARM64/x64, Windows x64\n\n\u003cbr\u003e\n\n## Development\n\nContributors: This project uses Bun internally for development:\n\n```bash\n# Install dependencies\nbun install\n\n# Run tests\nbun test\n\n# Run benchmarks\nbun tests/benchmarks/runner.js\n\n# Lint\nbun run lint\n```\n\n\u003cbr\u003e\n\n## Contributing\n\nContributions welcome! Fork the repo, create a feature branch, add tests, and submit a PR.\n\n\u003cbr\u003e\n\n---\n\n\u003cdiv align=\"center\"\u003e\n  \u003cp\u003e\n    \u003cb\u003eMIT License\u003c/b\u003e — Copyright (c) 2025 Namastex Labs\n  \u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://github.com/namastexlabs/pgserve\"\u003eGitHub\u003c/a\u003e •\n    \u003ca href=\"https://www.npmjs.com/package/pgserve\"\u003enpm\u003c/a\u003e •\n    \u003ca href=\"https://github.com/namastexlabs/pgserve/issues\"\u003eIssues\u003c/a\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n    Made with love by \u003ca href=\"https://namastex.ai\"\u003eNamastex Labs\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnamastexlabs%2Fpgserve","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnamastexlabs%2Fpgserve","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnamastexlabs%2Fpgserve/lists"}