Skip to content

Schema Validation

Synkro supports payload validation through a simple SchemaValidator interface. Validators run at publish time (for global schemas) and at dispatch time (for per-event schemas), catching invalid data before it reaches your handlers.

SchemaValidator type

type SchemaValidator = (payload: unknown) => void;

A schema validator is a function that receives the payload and throws if the payload is invalid. If it returns without throwing, the payload is considered valid.

Global schemas

Register schemas in the schemas config object. These are validated when synkro.publish() is called:

const synkro = await Synkro.start({
transport: "in-memory",
schemas: {
"order:placed": (payload) => {
if (!payload || typeof payload !== "object") {
throw new Error("Payload must be an object");
}
if (!("orderId" in payload)) {
throw new Error("orderId is required");
}
},
},
});

Per-event schemas

Attach a schema to an individual event definition. Per-event schemas are validated at both publish and dispatch time:

const synkro = await Synkro.start({
transport: "in-memory",
events: [
{
type: "user:registered",
handler: async (ctx) => { /* ... */ },
schema: (payload) => {
if (!payload?.email) throw new Error("email is required");
},
},
],
});

Using with validation libraries

import { z } from "zod";
const OrderSchema = z.object({
orderId: z.string(),
items: z.array(z.object({
sku: z.string(),
qty: z.number().positive(),
})),
total: z.number().positive(),
});
const synkro = await Synkro.start({
transport: "in-memory",
schemas: {
"order:placed": (payload) => OrderSchema.parse(payload),
},
});

Validation timing

Schema locationValidated at publishValidated at dispatch
schemas (global)YesNo
events[].schema (per-event)NoYes

Global schemas catch invalid payloads early, before the message enters the transport. Per-event schemas provide an additional check at the handler level.