Absurd - Absurd
Skip to content
Guide
SDKs
Patterns
Tools
Absurd
Absurd is a Postgres-native durable workflow system. It moves the complexity of<br>durable execution into the database layer via stored procedures, keeping SDKs<br>lightweight and language-agnostic. The core principle is to handle tasks that<br>may run for minutes, days, or years without losing state.
All you need is a Postgres database and the single<br>absurd.sql<br>schema file. No extra services, no message brokers, no coordination layer.<br>SDKs stay simple too.
… because it's absurd how much you can over-design such a simple thing.
How It Works
A task dispatches onto a queue from where a worker picks it up.<br>Tasks are subdivided into steps that act as checkpoints. Once a step<br>completes successfully its return value is persisted and the step won't execute<br>again. If a task fails, it retries from the last checkpoint.
Tasks can also sleep (suspend until a time) or await events (suspend<br>until a named event is emitted). Events are cached — first emit wins — making<br>them race-free.
TypeScriptPythonGo
import { Absurd } from 'absurd-sdk';
const app = new Absurd();
app.registerTask({ name: 'order-fulfillment' }, async (params, ctx) => {<br>const payment = await ctx.step('process-payment', async () => {<br>return { paymentId: `pay-${params.orderId}`, amount: params.amount };<br>});
const shipment = await ctx.awaitEvent(<br>`shipment.packed:${params.orderId}`,<br>);
await ctx.step('send-notification', async () => {<br>return {<br>sentTo: params.email,<br>trackingNumber: shipment.trackingNumber,<br>};<br>});
return {<br>orderId: params.orderId,<br>payment,<br>trackingNumber: shipment.trackingNumber,<br>};<br>});
await app.startWorker();
from absurd_sdk import Absurd
app = Absurd()
@app.register_task(name="order-fulfillment")<br>def process_order(params, ctx):<br>def process_payment():<br>return {<br>"payment_id": f"pay-{params['order_id']}",<br>"amount": params["amount"],
payment = ctx.step("process-payment", process_payment)
shipment = ctx.await_event(f"shipment.packed:{params['order_id']}")
def send_notification():<br>return {<br>"sent_to": params["email"],<br>"tracking_number": shipment["tracking_number"],
ctx.step("send-notification", send_notification)
return {<br>"order_id": params["order_id"],<br>"payment": payment,<br>"tracking_number": shipment["tracking_number"],
app.start_worker()
package main
import (<br>"context"<br>"log"
"github.com/earendil-works/absurd/sdks/go/absurd"<br>_ "github.com/jackc/pgx/v5/stdlib"
type OrderFulfillmentParams struct {<br>OrderID string `json:"order_id"`<br>Amount int `json:"amount"`<br>Email string `json:"email"`
type ShipmentEvent struct {<br>TrackingNumber string `json:"tracking_number"`
var orderFulfillmentTask = absurd.Task(<br>"order-fulfillment",<br>func(<br>ctx context.Context,<br>params OrderFulfillmentParams,<br>) (map[string]any, error) {<br>payment, err := absurd.Step(<br>ctx,<br>"process-payment",<br>func(ctx context.Context) (map[string]any, error) {<br>return map[string]any{<br>"payment_id": "pay-" + params.OrderID,<br>"amount": params.Amount,<br>}, nil<br>},<br>if err != nil {<br>return nil, err
shipment, err := absurd.AwaitEvent[ShipmentEvent](<br>ctx,<br>"shipment.packed:"+params.OrderID,<br>if err != nil {<br>return nil, err
if _, err := absurd.Step(<br>ctx,<br>"send-notification",<br>func(ctx context.Context) (map[string]any, error) {<br>return map[string]any{<br>"sent_to": params.Email,<br>"tracking_number": shipment.TrackingNumber,<br>}, nil<br>},<br>); err != nil {<br>return nil, err
return map[string]any{<br>"order_id": params.OrderID,<br>"payment": payment,<br>"tracking_number": shipment.TrackingNumber,<br>}, nil<br>},
func main() {<br>app, err := absurd.New(absurd.Options{<br>QueueName: "default",<br>DriverName: "pgx",<br>})<br>if err != nil {<br>log.Fatal(err)<br>defer app.Close()
app.MustRegister(orderFulfillmentTask)<br>if err := app.RunWorker(context.Background()); err != nil {<br>log.Fatal(err)
Quick Links
Quickstart — install the schema, create a queue, run your first task
Concepts — what durable execution is, plus tasks, steps, runs, events, and retry semantics
Storage — choose unpartitioned vs partitioned queues and automate partition lifecycle
Cleanup and Retention — set retention policies and automate cleanup with SQL, absurdctl, or cron
Comparison — where Absurd fits relative to PGMQ, Cadence, Temporal, Inngest, and DBOS
Patterns — practical recipes for common workflow and scheduling setups
Deploying and Rolling Rollouts — safely introduce new task names during rolling deploys
SDKs — available language SDKs
Tools Overview — utility tools