Type-safe contracts for Temporal.io
End-to-end type safety and automatic validation for workflows and activities
- ✅ End-to-end type safety — From contract to client, workflows, and activities
- ✅ Automatic validation — Zod schemas validate at all network boundaries
- ✅ Compile-time checks — TypeScript catches missing or incorrect implementations
- ✅ Better DX — Autocomplete, refactoring support, inline documentation
- ✅ Child workflows — Type-safe child workflow execution with neverthrow's
ResultAsync - ✅ Result pattern — Explicit error handling without exceptions, powered by neverthrow
- 🚧 Nexus support — Cross-namespace operations (planned for v0.5.0)
// Define contract once
const contract = defineContract({
taskQueue: "orders",
workflows: {
processOrder: {
input: z.object({ orderId: z.string() }),
output: z.object({ success: z.boolean() }),
activities: {
processPayment: {
input: z.object({ orderId: z.string() }),
output: z.object({ transactionId: z.string() }),
},
},
},
},
});
// Implement activities with neverthrow's ResultAsync
import { declareActivitiesHandler, ApplicationFailure } from "@temporal-contract/worker/activity";
import { ResultAsync } from "neverthrow";
const activities = declareActivitiesHandler({
contract,
activities: {
processPayment: ({ orderId }) =>
ResultAsync.fromPromise(paymentService.process(orderId), (error) =>
ApplicationFailure.create({
type: "PAYMENT_FAILED",
message: error instanceof Error ? error.message : "Payment failed",
...(error instanceof Error ? { cause: error } : {}),
}),
).map((txId) => ({ transactionId: txId })),
},
});
// Call from client - fully typed everywhere
const result = await client.executeWorkflow("processOrder", {
workflowId: "order-123",
args: { orderId: "ORD-123" }, // ✅ TypeScript knows!
});# Core packages
pnpm add @temporal-contract/contract @temporal-contract/worker @temporal-contract/client
# Result/ResultAsync — peer dep used by worker/client APIs
pnpm add neverthrow📖 Read the full documentation →
| Package | Description |
|---|---|
| @temporal-contract/contract | Contract builder and type definitions |
| @temporal-contract/worker | Type-safe worker with automatic validation |
| @temporal-contract/client | Type-safe client for consuming workflows |
| @temporal-contract/testing | Testing utilities for integration tests |
temporal-contract uses neverthrow end-to-end (workflows, activities, and the typed client) for explicit error handling via Result and ResultAsync. Migrating from a previous release that used @swan-io/boxed? See Migrating to neverthrow.
See CONTRIBUTING.md.
MIT