Skip to main content
The PostgreSQL backend is recommended for production. It supports multiple concurrent workers, provides strong durability guarantees, and scales with your application.

Install

The PostgreSQL backend requires the postgres driver. Install it alongside OpenWorkflow:
npm i openworkflow postgres

Setup

import { OpenWorkflow } from "openworkflow";
import { BackendPostgres } from "openworkflow/postgres";

const backend = await BackendPostgres.connect(
  process.env.OPENWORKFLOW_POSTGRES_URL, // e.g., "postgresql://user:pass@localhost:5432/mydb"
);

const ow = new OpenWorkflow({ backend });

Connection URL

The connection URL follows the standard PostgreSQL format:
postgresql://[user]:[password]@[host]:[port]/[database]
Examples:
  • Local: postgresql://postgres:postgres@localhost:5432/openworkflow
  • With SSL: postgresql://user:[email protected]:5432/db?sslmode=require

Configuration Options

const backend = await BackendPostgres.connect(url, {
  // Namespace for multi-tenant isolation (default: "default")
  namespaceId: "production",

  // Database schema for OpenWorkflow tables (default: "openworkflow")
  schema: "openworkflow",

  // Whether to run migrations on connect (default: true)
  runMigrations: true,
});

Migrations

By default, BackendPostgres.connect() runs database migrations automatically. This creates the configured schema (default: openworkflow) and required tables. To disable automatic migrations:
const backend = await BackendPostgres.connect(url, {
  runMigrations: false,
});
When disabled, ensure you run migrations separately before starting workers.

Schema

OpenWorkflow creates tables in the configured schema (default: openworkflow):
  • <schema>.workflow_runs - Stores workflow run state
  • <schema>.step_attempts - Stores step execution history
This keeps OpenWorkflow data separate from your application tables.

Namespaces

Use namespaceId to isolate environments or tenants:
// Production environment
const prodBackend = await BackendPostgres.connect(url, {
  namespaceId: "production",
});

// Staging environment (same database, different namespace)
const stagingBackend = await BackendPostgres.connect(url, {
  namespaceId: "staging",
});
See Namespaces for more details.

Config File Example

For use with the CLI, create openworkflow.config.ts:
import { defineConfig } from "@openworkflow/cli";
import { BackendPostgres } from "openworkflow/postgres";

export default defineConfig({
  backend: await BackendPostgres.connect(
    process.env.OPENWORKFLOW_POSTGRES_URL!,
  ),
  dirs: ["./openworkflow"],
});

Connection Pooling

The PostgreSQL backend uses connection pooling internally. For most applications, the default pool settings work well. The pool is managed automatically and connections are reused across workflow executions.

Requirements

  • PostgreSQL 14 or later
  • The connecting user needs permissions to:
    • Create schemas (for migrations)
    • Create tables (for migrations)
    • Read/write to the configured schema (default: openworkflow)