Skip to content

pgflow 0.5.4: Context - Simplify Your Handler Functions

Context object simplifying handler functions with platform resources

Workers now pass a context object as a second parameter to all handlers, providing ready-to-use database connections, environment variables, and Supabase clients.

Previously, handlers relied on global singletons or manual resource initialization:

// Before: Global resources that complicated testing and lifecycle management
import { sql } from '../db.js';
import { supabase } from '../supabase-client.js';
// After: Clean dependency injection via context
async 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
});
}

Core resources (always available):

  • env - Environment variables
  • shutdownSignal - AbortSignal for graceful shutdown
  • rawMessage - 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)
  1. Zero Configuration - No connection boilerplate
  2. Managed Resources - pgflow handles pooling and lifecycle
  3. Type Safety - Full TypeScript support
  4. Testable - Mock only what you use:
// Handler uses only env? Test with only env:
await handler(input, { env: { API_KEY: 'test' } });

Existing handlers continue to work. Add the context parameter when you need platform resources:

// Old handlers work fine
async function handler(input) { return { ok: true }; }
// New handlers get context
async 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