Postgres

Use the first-party pg adapter for direct SQL-backed Paymesh persistence with transactions, raw persistence, migrations, and operational plugins.

Overview

@paymesh/postgres is the most direct first-party adapter. It uses pg underneath and implements the full Paymesh database driver contract without an ORM layer in between.

Installation

npm install @paymesh/postgres pg

Usage

src/lib/paymesh.ts
import { createClient } from "paymesh";
import { postgres } from "@paymesh/postgres";
import { stripe } from "@paymesh/stripe";

export const paymesh = createClient({
  provider: stripe({
    secret: "sk_test_123",
    webhookSecret: "whsec_123",
  }),
  database: postgres("postgres://postgres:postgres@localhost:5432/paymesh", {
    persistRaw: true,
  }),
});

Accepted connection inputs

The first argument accepts either:

  • a connection string — the adapter creates and owns the internal pg.Pool, closing it on database.close()
  • an existing pg.Pool instance — ownership stays with your app; database.close() is a no-op

Passing a connection string

postgres("postgres://postgres:postgres@localhost:5432/paymesh")

Passing an existing Pool

import { Pool } from "pg";

const pool = new Pool({
  connectionString: "postgres://...",
  max: 20,
});

postgres(pool)

Options

The second argument accepts persistRaw plus any option that pg.Pool accepts (max, idleTimeoutMillis, connectionTimeoutMillis, ssl, etc.).

OptionDefaultDescription
persistRawfalseStores raw provider payloads alongside normalized records.
max10Maximum number of clients in the pool.
idleTimeoutMillis10000Close idle clients after this many milliseconds.
connectionTimeoutMillis10000Timeout for acquiring a new connection.
sslundefinedboolean or TLS configuration object.
any PoolConfig keyForwarded directly to the internal Pool.

Pool-scoped options are forwarded to the internal Pool when a connection string is given, and silently ignored when an existing Pool instance is passed.

postgres("postgres://postgres:postgres@localhost:5432/paymesh", {
  persistRaw: true,
  max: 15,
  idleTimeoutMillis: 30000,
  ssl: { rejectUnauthorized: false },
})

Transactions

The adapter creates a dedicated pg client for database.transaction() and wraps the callback in BEGIN, COMMIT, and ROLLBACK.

src/server/transaction.ts
await paymesh.database?.transaction(async (tx) => {
  await tx.repositories.customers.upsert(paymesh.schema, {
    id: "cus_123",
    provider: "stripe",
    email: "team@example.com",
  });
});

Error behavior

Database query and transaction failures are wrapped into PaymeshError with code database_error.

That means callers can handle persistence issues through the same error type used by the rest of Paymesh.

When to choose this adapter

Use @paymesh/postgres when:

  • you want the leanest stack
  • your application is already comfortable with direct SQL or pg
  • you want minimal abstraction between Paymesh and PostgreSQL

If your team already standardized on Drizzle or Prisma, use those adapters instead.