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

@fahren/postgres

v0.1.0-alpha.1

Published

Implement multi-tenant strategies over PostgreSQL.

Readme

@fahren/postgres

Implement multi-tenant strategies over PostgreSQL.

Installation

# Using npm
npm install @fahren/postgres

# Using yarn
yarn add @fahren/postgres

# Using pnpm
pnpm add @fahren/postgres

Isolation Strategies

Row-Level Security (RLS)

Uses PostgreSQL's Row-Level Security to separate tenant data within the same tables.

Prerequisite: Before using RLS, you must either:

  • Run setup() to configure RLS policies for your tables, or
  • Call createTenant() at least once with autoSetup: true in the options
import Postgres from "@fahren/postgres";

const poolConfig = {
  connectionString: "postgres://user:password@host:port",
};
const management = new Postgres().withRlsIsolation().forManagement({
  poolConfig,
  options: {
    provision: {
      autoSetup: true,
    },
  },
  id: resourceId,
});
await management.createTenant("tenant123");

const postgresTenants = new Postgres()
  .withRlsIsolation()
  .forTenants({ poolConfig });

const tenantClient = await postgresTenants.queryAs(
  "tenant123",
  "SELECT * FROM users"
);

Schema-Based Isolation

Creates separate schemas for each tenant within the same database.

import Postgres from "@fahren/postgres";
import { AwsSecretsManager } from "@fahren/secrets";

const poolConfig = {
  connectionString: "postgres://user:password@host:port",
};
const postgres = new Postgres().withSchemaIsolation();
const management = postgres.forManagement({
  poolConfig,
  secrets: {
    provider: new AwsSecretsManager(),
  },
  id: resourceId,
});

const tenants = postgres.forTenants({
  secrets: {
    provider: new AwsSecretsManager(),
  },
  id: resourceId,
});

// Creates schema "tenant_acme_inc" and role
await management.createTenant("acme_inc");

// Automatically uses the correct schema
const tenantClient = await postgres.getClientFor("acme_inc");
await tenants.query("SELECT * FROM users");

// Removes the schema and role
await management.deleteTenant("acme_inc");

Database-Based Isolation

Creates separate databases for each tenant, providing maximum isolation.

import Postgres from "@fahren/postgres";
import { AwsSecretsManager } from "@fahren/secrets";

const poolConfig = {
  connectionString: "postgres://user:password@host:port",
};
const secretsProvider = new AwsSecretsManager();
const postgres = new Postgres().withDatabaseIsolation().forManagement({
  poolConfig,
  secrets: {
    provider: secretsProvider,
  },
});

// Creates database "tenant_acme_inc" and role
await postgres.createTenant("acme_inc");

// Automatically connects to the right database using secrets
const tenantClient = await postgres.getClientFor("acme_inc");
await tenantClient.query("SELECT * FROM analytics");

// Removes the database and role
await postgres.deleteTenant("acme_inc");

PgBouncer

If you're using PgBouncer as a connection pooler, you should use the PgBouncer-specific client:

import Postgres from "@fahren/postgres";

const postgres = new Postgres()
  .withPgBouncer()
  .withRlsIsolation()
  .forTenants({
    poolConfig: {
      connectionString: "postgres://user:password@host:5432/db",
      poolMode: "session_mode", // or "transaction_mode"
    },
  });

PgBouncer Limitations

  • Transaction Mode: When using transaction_mode:

    • Database-based isolation is not supported (cannot create/delete databases inside transactions)
    • Each query is automatically wrapped in a transaction
    • Connections are returned to the pool after each query
  • Session Mode: When using session_mode:

    • All isolation strategies are supported
    • Connections maintain their session state
    • You must manually manage transactions
  • Role Management: When creating tenants with login-enabled roles, you must manually update PgBouncer to grant access to PostgreSQL.

Features

  • Multiple Isolation Strategies: Choose between RLS, schema, or database-based isolation
  • Automatic Tenant Management: Create and delete tenant resources with a single call
  • Secrets Integration: Secure storage of tenant credentials using secrets providers
  • Connection Pooling: Efficient connection management for each tenant
  • Role-Based Access Control: Automatic role creation and permission management

Security Considerations

Row-Level Security (RLS)

  • Pros:
    • Efficient resource utilization
    • Simplified schema management
    • Easy global queries across all tenants
  • Cons:
    • Requires careful policy configuration
    • Added WHERE clause overhead on queries

Schema-Based Isolation

  • Pros:
    • Better isolation than RLS
    • Simplified backup and restore per tenant
    • Allows for tenant-specific schema modifications
  • Cons:
    • More complex global queries
    • Higher number of database objects

Database-Based Isolation

  • Pros:
    • Maximum isolation level
    • Tenant-specific database configuration
  • Cons:
    • Higher resource requirements
    • More complex backup strategies
    • More overhead for cross-tenant operations

Related Resources