npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

postgres-memory-server

v0.2.2

Published

spin up an actual/real postgres server programmatically from within nodejs, for testing or mocking during development

Readme

postgres-memory-server

Spin up a disposable real PostgreSQL or ParadeDB instance in tests with a tiny API inspired by mongodb-memory-server and redisjson-memory-server.

This package does not emulate Postgres. It starts an actual PostgreSQL process using native binaries — no Docker required.

Why this exists

For Postgres extension-heavy workloads, especially ParadeDB + pgvector, a real database is usually what you want in tests:

  • no shared local database contamination
  • deterministic integration tests
  • realistic extension behavior
  • straightforward CI/CD setup — no Docker daemon needed
  • one API for plain Postgres and ParadeDB

Features

  • Start a disposable Postgres instance with create() — no Docker
  • PostgreSQL binaries bundled via embedded-postgres
  • ParadeDB pg_search and pgvector extensions auto-downloaded from official releases
  • Get a ready-to-use connection string with getUri()
  • Run SQL strings, SQL files, or a migrations directory
  • Snapshot and restore database state between tests
  • Extension binaries cached in ~/.cache/postgres-memory-server/
  • CLI for local scripts and debugging

Requirements

  • Node.js 20+

That's it. No Docker, no system Postgres installation needed.

Install

npm install -D postgres-memory-server

The pg client library is included as a dependency.

Quick start

import { PostgresMemoryServer } from "postgres-memory-server";
import { Client } from "pg";

const db = await PostgresMemoryServer.create();

const client = new Client({ connectionString: db.getUri() });
await client.connect();
await client.query("select 1");
await client.end();

await db.stop();

ParadeDB quick start

import { PostgresMemoryServer } from "postgres-memory-server";

const db = await PostgresMemoryServer.createParadeDb();

await db.runSql(`
  CREATE TABLE documents (
    id bigserial primary key,
    title text not null,
    content text not null,
    embedding vector(3)
  );
`);

await db.stop();

By default, the ParadeDB preset automatically downloads and installs the extensions, then runs:

CREATE EXTENSION IF NOT EXISTS pg_search;
CREATE EXTENSION IF NOT EXISTS vector;

Extension binaries are downloaded once and cached in ~/.cache/postgres-memory-server/.

How it works

Instead of Docker containers, this package uses:

  1. embedded-postgres — bundles PostgreSQL binaries as npm packages (~10MB). The PostgreSQL version is determined by the installed embedded-postgres npm package version (e.g., [email protected] = PostgreSQL 18).

  2. Native extension installation — for the ParadeDB preset, pg_search and pgvector extension binaries are downloaded from their official release channels, extracted, and installed into the embedded PostgreSQL directory.

  3. Template database snapshotssnapshot() and restore() use PostgreSQL's native CREATE DATABASE ... TEMPLATE for fast, zero-copy test isolation.

PostgreSQL version

The PostgreSQL version is tied to the embedded-postgres npm package version. To use a specific PG version:

# PG 18 (default with latest embedded-postgres)
npm install -D embedded-postgres

# PG 17
npm install -D [email protected]

# PG 16
npm install -D [email protected]

Platform support

| Platform | Postgres | ParadeDB pg_search | pgvector | |----------|----------|--------------------|----------| | macOS arm64 (Apple Silicon) | Yes | Yes | Yes | | macOS x64 (Intel) | Yes | No | Yes | | Linux x64 | Yes | Yes | Yes | | Linux arm64 | Yes | Yes | Yes | | Windows x64 | Yes | No | No |

API

PostgresMemoryServer.create(options?)

Create a disposable Postgres instance.

const db = await PostgresMemoryServer.create({
  database: "testdb",
  username: "testuser",
  password: "testpassword",
});

PostgresMemoryServer.createPostgres(options?)

Convenience alias for the plain Postgres preset.

const db = await PostgresMemoryServer.createPostgres();

PostgresMemoryServer.createParadeDb(options?)

Starts a Postgres instance with ParadeDB extensions (pg_search + pgvector).

const db = await PostgresMemoryServer.createParadeDb();

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | preset | "postgres" \| "paradedb" | "postgres" | Controls default extensions | | version | string | — | ParadeDB extension version (e.g., "0.22.5") | | database | string | "testdb" | Database name | | username | string | "testuser" | Username | | password | string | "testpassword" | Password | | extensions | string[] | preset default | Extensions to create | | initSql | string[] | [] | SQL statements to run after setup |

createJestGlobalSetup(options?)

Starts one disposable database process for a Jest run and injects its URI into DATABASE_URL by default.

createJestGlobalTeardown(options?)

Stops the process started by createJestGlobalSetup().

Instance methods

  • getUri() — connection string (postgres://...)
  • getHost() — always localhost
  • getPort() — randomly assigned free port
  • getDatabase()
  • getUsername()
  • getPassword()
  • getConnectionOptions(){ host, port, database, user, password }
  • getImage() — descriptive label (e.g., "postgres:18")
  • query(text, params?) — execute a query and return rows
  • withClient(callback) — direct access to a pg.Client
  • runSql(sql) — execute one or more SQL statements
  • runSqlFile(filePath) — execute SQL from a file
  • runMigrationsDir(dirPath) — run .sql files in lexicographic order
  • snapshot() — create a restore point
  • restore() — restore to last snapshot
  • stop() — shut down the PostgreSQL process

Snapshots

const db = await PostgresMemoryServer.create();

await db.runSql([
  "create table users (id serial primary key, email text not null)",
  "insert into users (email) values ('[email protected]')",
]);

await db.snapshot();

await db.runSql("insert into users (email) values ('[email protected]')");

await db.restore();

const result = await db.query<{ count: string }>(
  "select count(*)::text as count from users",
);
console.log(result.rows[0]?.count); // 1

Snapshots use PostgreSQL template databases under the hood. Use a non-system database name (the default testdb works).

Running SQL files or migrations

await db.runSqlFile("./sql/001_init.sql");
await db.runMigrationsDir("./sql/migrations");

Migration files are run in lexicographic order.

CLI

npx postgres-memory-server --preset paradedb

Example output:

POSTGRES_MEMORY_SERVER_URI=postgres://testuser:testpassword@localhost:54329/testdb
POSTGRES_MEMORY_SERVER_HOST=localhost
POSTGRES_MEMORY_SERVER_PORT=54329
POSTGRES_MEMORY_SERVER_DATABASE=testdb
POSTGRES_MEMORY_SERVER_USERNAME=testuser
POSTGRES_MEMORY_SERVER_PASSWORD=testpassword

Press Ctrl+C to stop the server.

CLI flags

--preset postgres|paradedb
--version <tag>
--database <name>
--username <name>
--password <password>
--extension <name>      # repeatable
--init-file <path>      # repeatable
--json

Jest global setup

// jest.global-setup.ts
import { createJestGlobalSetup } from "postgres-memory-server";

export default createJestGlobalSetup({
  preset: "paradedb",
});
// jest.global-teardown.ts
import { createJestGlobalTeardown } from "postgres-memory-server";

export default createJestGlobalTeardown();
// jest.config.ts
import type { Config } from "jest";

const config: Config = {
  globalSetup: "./jest.global-setup.ts",
  globalTeardown: "./jest.global-teardown.ts",
  testEnvironment: "node",
};

export default config;

After setup runs, your tests can connect through process.env.DATABASE_URL.

Vitest example

import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
import { PostgresMemoryServer } from "postgres-memory-server";

describe("db", () => {
  let db: PostgresMemoryServer;

  beforeAll(async () => {
    db = await PostgresMemoryServer.create();
    await db.runSql(`
      create table notes (
        id serial primary key,
        body text not null
      );
    `);
    await db.snapshot();
  });

  beforeEach(async () => {
    await db.restore();
  });

  afterAll(async () => {
    await db.stop();
  });

  it("starts from a clean snapshot", async () => {
    await db.runSql("insert into notes (body) values ('hello')");
    const result = await db.query<{ count: string }>(
      "select count(*)::text as count from notes",
    );
    expect(result.rows[0]?.count).toBe("1");
  });
});

Migrating from v0.1.0 (Docker-based)

v0.2.0 replaces Docker containers with native binaries. Key changes:

| v0.1.0 | v0.2.0 | |--------|--------| | Requires Docker daemon | No Docker needed | | @testcontainers/postgresql | embedded-postgres | | PG version via version option | PG version via embedded-postgres npm version | | image option for Docker images | image option deprecated (ignored) | | Container snapshots | Template database snapshots |

Breaking changes:

  • The image option is deprecated and ignored. Remove it from your code.
  • The version option for the postgres preset is ignored — install the desired embedded-postgres@<version> package instead.
  • The version option for the paradedb preset now refers to the ParadeDB extension version (e.g., "0.22.5"), not the Docker image tag.

No changes needed if you only used create(), createPostgres(), or createParadeDb() with just database, username, password, or extensions options.

Caveats

  • The PostgreSQL version is determined by the installed embedded-postgres npm package, not by a runtime option.
  • ParadeDB pg_search requires macOS arm64 or Linux. Intel Macs and Windows are not supported for ParadeDB.
  • Snapshot and restore terminate other connections to the database during the operation.
  • The package is ESM-only.

Test scripts

npm run test:postgres
npm run test:paradedb

License

MIT