Durable Execution - Tasks survive crashes and restarts through automatic step memoization
Multiple Triggers - Invocable APIs, cron schedules, custom events, and database triggers
Workflows - Invoke child tasks and wait for results with full type safety
Performance - Process up to 20,000 jobs per second with just Postgres
Type-Safety - Share common event and task schemas across your services
Simple Infrastructure - No Redis, no message queues - just Postgres
Postgres Conductor is available on npm:
pnpm install pgconductor-jsHere's a minimal example to get you started:
Tasks are defined with a name and optional payload schema using Standard Schema:
import { z } from "zod";
import { defineTask } from "pgconductor-js";
const greetTask = defineTask({
name: "greet",
payload: z.object({ name: z.string() }),
});The Conductor manages task definitions and the database connection:
import { Conductor } from "pgconductor-js";
import { TaskSchemas } from "pgconductor-js";
const sql = postgres();
const conductor = Conductor.create({
connectionString: "postgres://localhost:5432/mydb",
tasks: TaskSchemas.fromSchema([greetTask])
});Create a task handler that defines what happens when the task runs:
const greet = conductor.createTask(
{ name: "greet" },
{ invocable: true }, // Allow invocation
async (event, ctx) => {
const { name } = event.payload;
ctx.logger.info(`Hello, ${name}!`);
}
);The Orchestrator runs workers that execute tasks:
import { Orchestrator } from "pgconductor-js";
const orchestrator = Orchestrator.create({
conductor,
tasks: [greet],
});
await orchestrator.start();
console.log("Worker running. Press Ctrl+C to stop.");
await orchestrator.stopped;In a separate process, invoke the task via an instance of the Conductor:
await conductor.invoke(
{ name: "greet" },
{ name: "World" }
);