pgflow 0.5.4: Context - Simplify Your Handler Functions
Workers now pass a context object as a second parameter to all handlers, providing ready-to-use database connections, environment variables, and Supabase clients.
The Problem We Solved
Section titled “The Problem We Solved”Previously, handlers relied on global singletons or manual resource initialization:
// Before: Global resources that complicated testing and lifecycle managementimport { sql } from '../db.js';import { supabase } from '../supabase-client.js';
// After: Clean dependency injection via contextasync function processPayment(input, ctx) { const [payment] = await ctx.sql` SELECT * FROM payments WHERE id = ${input.paymentId} `; await ctx.serviceSupabase.from('audit_logs').insert({ action: 'payment_processed', payment_id: input.paymentId });}What’s in the Context
Section titled “What’s in the Context”Core resources (always available):
env- Environment variablesshutdownSignal- AbortSignal for graceful shutdownrawMessage- pgmq message metadata (msg_id, read_ct, etc.)stepTask- Step execution details (flows only)
Supabase resources:
sql- PostgreSQL client (postgres.js)anonSupabase- Client with anon key (respects RLS)serviceSupabase- Client with service role (bypasses RLS)
Key Benefits
Section titled “Key Benefits”- Zero Configuration - No connection boilerplate
- Managed Resources - pgflow handles pooling and lifecycle
- Type Safety - Full TypeScript support
- Testable - Mock only what you use:
// Handler uses only env? Test with only env:await handler(input, { env: { API_KEY: 'test' } });Migration
Section titled “Migration”Existing handlers continue to work. Add the context parameter when you need platform resources:
// Old handlers work fineasync function handler(input) { return { ok: true }; }
// New handlers get contextasync function handler(input, ctx) { const data = await ctx.sql`SELECT * FROM table`; return { ok: true, count: data.length };}Updated packages: @pgflow/edge-worker and @pgflow/dsl