Postgres World

The PostgreSQL world is a reference implementation of a World that's fully backed by PostgreSQL, including job processing (using pg-boss) and streaming (using PostgreSQL's NOTIFY and LISTEN).

This world is designed for long-running processes, so it can receive and dispatch events from a PostgreSQL database, and isn't meant to be deployed on serverless platforms like Vercel due to that nature.

Installation

Install the @workflow/world-postgres package:

npm install @workflow/world-postgres

Add Environment Variables

Add the following environment variables to your .env file required for workflows:

WORKFLOW_TARGET_WORLD="@workflow/world-postgres"
WORKFLOW_POSTGRES_URL="postgres://postgres:password@db.yourdb.co:5432/postgres"
WORKFLOW_POSTGRES_JOB_PREFIX="workflow_"
WORKFLOW_POSTGRES_WORKER_CONCURRENCY=10

The world configuration is automatically read from environment variables:

  • WORKFLOW_TARGET_WORLD - Required, specifies which world implementation to use
  • WORKFLOW_POSTGRES_URL - PostgreSQL connection string (defaults to postgres://world:world@localhost:5432/world)
  • WORKFLOW_POSTGRES_JOB_PREFIX - Prefix for queue job names
  • WORKFLOW_POSTGRES_WORKER_CONCURRENCY - Number of concurrent workers (defaults to 10 if not specified)

Set Up the Database Schema

Run the setup script to create the required database tables:

pnpm exec workflow-postgres-setup

This will create the following tables in your PostgreSQL database:

  • workflow_runs - Stores workflow execution state
  • workflow_events - Stores workflow events
  • workflow_steps - Stores workflow step state
  • workflow_hooks - Stores workflow hooks
  • workflow_stream_chunks - Stores streaming data

You should see output like:

🔧 Setting up database schema...
📍 Connection: postgres://postgres:****@db.yourcloudprovider.co:5432/postgres
✅ Database schema created successfully!

Initialize the PostgreSQL World

Starting the PostgreSQL World will vary between different frameworks. The main idea is starting the PostgreSQL World on server startup.

Here are some examples of what it might look like:

Next.js

Create an instrumentation.ts file in your project root to initialize and start the world:

instrumentation.ts
export async function register() {
  if (process.env.NEXT_RUNTIME !== "edge") {
    // Dynamic import to avoid edge runtime bundling issues
    console.log('Starting Postgres World...');
    const { getWorld } = await import("workflow/runtime");
    await getWorld().start?.();
    console.log('Postgres World started');
  }
}

Learn more about Next.js Instrumentation.

SvelteKit

Create a file src/hooks.server.ts:

src/hooks.server.ts
import type { ServerInit } from '@sveltejs/kit';

export const init: ServerInit = async () => {
  if (process.env.WORKFLOW_TARGET_WORLD === '@workflow/world-postgres') {
    // Dynamic import to avoid edge runtime bundling issues
    const { getWorld } = await import('workflow/runtime');
    console.log('Starting Postgres World...');
    await getWorld().start?.();
    console.log('Postgres World started');
  }
};

Learn more about SvelteKit Hooks.

Nitro-based Apps

Create a plugin to start the PostgreSQL World. This will be invoked when the Nitro server starts.

plugins/start-pg-world.ts
import { defineNitroPlugin } from 'nitro/~internal/runtime/plugin';

export default defineNitroPlugin(async () => {
  if (process.env.WORKFLOW_TARGET_WORLD === '@workflow/world-postgres') {
    // Dynamic import to avoid edge runtime bundling issues
    console.log('Starting Postgres World...');
    const { getWorld } = await import('workflow/runtime');
    await getWorld().start?.();
    console.log('Postgres World started');
  }
});

Add the plugin to your nitro.config.ts file. This enables the plugin:

nitro.config.ts
import { defineNitroConfig } from 'nitropack';

export default defineNitroConfig({
  // ... your nitro config
  modules: ['workflow/nitro'],
  plugins: ['plugins/start-pg-world.ts'],
});

Learn more about Nitro Plugins

How it works

The Postgres World uses PostgreSQL as a durable backend for workflow execution:

  • Job Queue: Uses pg-boss for reliable job processing
  • Event Streaming: Leverages PostgreSQL's NOTIFY/LISTEN for real-time event distribution
  • State Persistence: All workflow state is stored in PostgreSQL tables
  • Worker Management: Supports configurable concurrent workers for job processing

This setup ensures that your workflows can survive application restarts and failures, with all state reliably persisted to your PostgreSQL database.