Worktree-isolated local Postgres for Vite+, Nx, and CedarJS, powered by autopg.
Published on npm as @cedarjs/pg.
Alpha (
0.1.0-alpha.0): APIs may change. Install with thealphadist-tag.
autopg runs embedded PostgreSQL 18 (not WASM) with real concurrent connections. No credentials, zero config, and databases are provisioned on first use. Any client works (psql, node-postgres, Prisma, Drizzle, TypeORM).
| Use case | What you get |
|---|---|
| Local development | PostgreSQL without Docker |
| Integration testing | Real PostgreSQL, not mocks |
| CI/CD pipelines | Fresh databases per test run |
| E2E testing | Isolated database for Playwright / Cypress |
cedar-pg gives each git worktree its own database and role on that autopg host (readable names, leases, teardown) so parallel checkouts do not share one DB:
- 1 database per git worktree (visible in
\lascpg_…) - dev DBs persist across restarts; test DBs drop on dispose
- First-class Vite+ Task + Nx / Vitest / Jest adapters
postinstallensures the pinnedautopgbinary when missing
| Layer | Responsibility |
|---|---|
| autopg | Embedded Postgres host (concurrent, zero-config, auto-provision) |
| cedar-pg | Per-worktree CREATE DATABASE / role, DATABASE_URL, dispose + GC |
npm install -D @cedarjs/pg@alpha
# or: pnpm add -D @cedarjs/pg@alpha
# or: yarn add -D @cedarjs/pg@alphacpg_<repo>_<worktree>_<mode>_<pathHash8>
Examples:
| Name | Meaning |
|---|---|
cpg_cedar_cedar_dev_a1b2c3d4 |
main cedar checkout, dev |
cpg_cedar_feat_auth_test_e5f67890 |
worktree feat-auth, test |
A running autopg host (installed automatically by postinstall, or manually).
The release pin lives in scripts/autopg-version (single source of truth for postinstall, CI binary install, and docs). Bump that file to upgrade:
# local / non-CI (upstream install.sh; may use pm2)
VER=$(tr -d '[:space:]' < scripts/autopg-version)
curl -fsSL "https://raw.githubusercontent.com/automagik-dev/autopg/${VER}/install.sh" \
| AUTOPG_VERSION="$VER" bashTypical flow: autopg daemon (or your usual host install) once per machine → cedarpg ensure per worktree → connect with the printed DATABASE_URL.
vp install
vp check
vp test
vp pack # → dist/ (dts + esm + cjs)
vp run smoke # build → npm-pack tarball → install + resolve exports
vp run smoke:pg # pack → Vitest + Jest adapters against real ephemeral Postgres# in this repo
vp pack
# in your app / Cedar
yarn add @cedarjs/pg@file:../cedar-pg
# or: pnpm pack && yarn add ./cedarjs-pg-0.1.0-alpha.0.tgzcedarpg ensure --mode=dev
cedarpg ensure --mode=test --print-env
cedarpg dispose --mode=test
cedarpg print-url --mode=dev
cedarpg gc # drop DBs whose worktree root is gone (uses ~/.cedarpg/registry)// vite.config.ts
import { defineConfig } from "vite-plus";
import { cedarPgTasks } from "@cedarjs/pg/vite-plus";
export default defineConfig({
run: {
tasks: {
...cedarPgTasks(),
test: {
command: "vp test",
dependsOn: ["db:ensure-test"],
env: ["DATABASE_URL", "TEST_DATABASE_URL"],
},
dev: {
command: "vp dev",
dependsOn: ["db:ensure"],
env: ["DATABASE_URL"],
},
},
},
});// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globalSetup: ["@cedarjs/pg/vitest"],
},
});// jest.config.cjs — standalone apps
module.exports = {
globalSetup: require.resolve("@cedarjs/pg/jest"),
globalTeardown: require.resolve("@cedarjs/pg/jest-teardown"),
// Jest globalSetup is a separate process — workers load DATABASE_URL from .cedarpg/test.env
setupFiles: [require.resolve("@cedarjs/pg/test-env")],
};If your runner already owns globalSetup (e.g. Prisma push/migrate after ensure), do not replace it with @cedarjs/pg/jest. Compose instead:
- In your
globalSetup: callensureIfNeededwhen opted in, then run migrations. - Add
setupFiles: [require.resolve('@cedarjs/pg/test-env')]so Jest workers seeDATABASE_URL. - In your
globalTeardown: calldispose({ mode: 'test', root }).
// framework globalSetup (sketch)
import { ensureIfNeeded } from "@cedarjs/pg";
if (process.env.CEDAR_PG === "1" || process.env.CEDAR_PG === "true") {
await ensureIfNeeded({
root: projectRoot, // e.g. getPaths().base
mode: "test",
setEnv: true, // this process (prisma) — workers use @cedarjs/pg/test-env
url: process.env.TEST_DATABASE_URL,
force: process.env.CEDAR_PG_FORCE === "1",
disabled: false, // framework opt-in; adapters alone use CEDAR_PG=0 opt-out
});
}
// … prisma db push / migrate …// jest-preset
setupFiles: [require.resolve("@cedarjs/pg/test-env")],Use exported STATE_DIRNAME (.cedarpg) / loadTestEnv(root?) instead of hardcoding the lease dir.
import { ensure, dispose, loadTestEnv, STATE_DIRNAME } from "@cedarjs/pg";
const { databaseUrl, databaseName, dispose: drop } = await ensure({ mode: "test" });
// … tests …
await drop();By default cedar-pg attaches to a live autopg host (autopg status). If none is live it runs bare autopg install (pm2) — fine for local machines, hostile to GitHub Actions (no pm2) and slower than RAM-backed CI.
In CI, cedar-pg starts an opinionated ephemeral host automatically when CI=true (or when forced). Callers just use ensure — no host options bag:
import { ensure } from "@cedarjs/pg";
// CI=true → install --no-pm2 --no-ui + detached postmaster (--ram on Linux /dev/shm)
const { databaseUrl } = await ensure({ mode: "test" });| Signal | Effect |
|---|---|
CEDAR_PG_EPHEMERAL_HOST=1 |
Prefer ephemeral start when no host is live (attach still wins) |
CEDAR_PG_EPHEMERAL_HOST=0 |
Force local attach / pm2 install (even if CI=true) |
unset + CI=true |
Prefer ephemeral when no host is live |
| otherwise | Local: attach if live, else bare autopg install |
Ephemeral recipe (not configurable via cedar-pg):
autopg install --no-pm2 --no-ui --port 55432 --data DIR- detached
autopg postmaster --port 55432 --socket-dir DIR --data DIR - Linux when
/dev/shmexists → also--ramandDIR=/dev/shm/cedar-pg-<uid> - otherwise → disk
DIRunder the OS temp dir (still owned, no pm2) - Ready when TCP accepts on the recipe port (not merely
autopg statusafter install)
If a host is already live, cedar-pg attaches and does not start another. The CI job owns ephemeral postmaster lifetime (runner teardown / /dev/shm); there is no cedar-pg host dispose API.
Prefer the composite action (cache + attested binary install, no pm2). Version defaults to this repo’s scripts/autopg-version:
- uses: actions/checkout@v6
# In cedar-pg:
- uses: ./.github/actions/setup-autopg
# From another repo (pin to a tag when publishing the action):
# - uses: cedarjs/cedar-pg/.github/actions/setup-autopg@mainSee .github/actions/setup-autopg for inputs (version, cache, token) and outputs.
The action runs scripts/ci-install-autopg.sh under the hood. For published-package consumers under CI=true without the Action, set CEDAR_PG_INSTALL_AUTOPG=1 so postinstall runs that same script (not upstream install.sh) — that flag alone is not enough when the package manager disables lifecycle scripts (--ignore-scripts, YARN_ENABLE_SCRIPTS=false, etc.). Prefer this Action, or bake the binary into the image.
| Var | Meaning |
|---|---|
AUTOPG_BIN |
Path to autopg |
AUTOPG_PG_USER / _PASSWORD |
Autopg superuser for admin URL (default postgres / postgres) |
CEDAR_PG=0 |
Disable auto-ensure in adapters |
TEST_DATABASE_URL |
Escape hatch: skip ensure for real external DBs (not cpg_* / file: / {…} / <…> template placeholders) |
CEDAR_PG_FORCE=1 |
Ignore external-URL escape hatch (use for real external DBs / Jest when you still want ensure) |
CEDAR_PG_EPHEMERAL_HOST |
1 force / 0 disable ephemeral host (auto when CI=true) |
CEDAR_PG_REGISTRY_DIR |
Override global lease registry (for gc) |
CEDAR_PG_SKIP_POSTINSTALL=1 |
Skip autopg install hook |
CEDAR_PG_INSTALL_AUTOPG=1 |
Under CI=true, run binary-only ci-install-autopg.sh from postinstall |
- Public API may change before
0.1.0. - End-to-end Postgres flows assume a working local
autopghost; unit tests do not start Postgres. CI runsvp run smoke:pgfor Vitest/Jest adapters against real Postgres (ephemeral cold-start when the runner has no live host; attach-wins otherwise). - State lives in product-owned
.cedarpg(worktree +~/.cedarpg/registry), not under autopg's~/.autopg/or a generic.pg. - Password salt (
cedar-pg\\0, scheme v1) is an opaque crypto constant; bump the scheme id to change it.