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.
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=10The world configuration is automatically read from environment variables:
WORKFLOW_TARGET_WORLD- Required, specifies which world implementation to useWORKFLOW_POSTGRES_URL- PostgreSQL connection string (defaults topostgres://world:world@localhost:5432/world)WORKFLOW_POSTGRES_JOB_PREFIX- Prefix for queue job namesWORKFLOW_POSTGRES_WORKER_CONCURRENCY- Number of concurrent workers (defaults to10if not specified)
Set Up the Database Schema
Run the setup script to create the required database tables:
pnpm exec workflow-postgres-setupThis will create the following tables in your PostgreSQL database:
workflow_runs- Stores workflow execution stateworkflow_events- Stores workflow eventsworkflow_steps- Stores workflow step stateworkflow_hooks- Stores workflow hooksworkflow_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:
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:
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.
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:
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.