Use .effect(...) when a procedure implementation should run as an Effect.
const getUser = effectProcedure
.input(z.object({ id: z.string() }))
.effect(function* ({ input }) {
const user = yield* UsersRepo.findById(input.id);
return user;
});
The handler receives the normal oRPC handler options, including input, context, errors, path, signal, and metadata.
Handler shape
const procedure = effectProcedure.effect(function* ({
input,
context,
errors,
path,
signal,
}) {
yield* Effect.logDebug("handling procedure", { path });
if (signal?.aborted) {
yield* Effect.logDebug("request was already aborted");
}
return { input, context, path, errorKeys: Object.keys(errors) };
});
Mix with standard oRPC handlers
You can put standard oRPC procedures and Effect procedures in the same router.
import { os } from "@orpc/server";
export const router = {
health: os.handler(() => "ok"),
users: {
get: effectProcedure.effect(function* ({ input }) {
return yield* UsersRepo.findById(input.id);
}),
},
};
Use .handler(...) for plain synchronous or async procedures. Use
.effect(...) when the handler needs Effect services, typed Effect failures,
tracing, or fiber context.
Next steps