RPC
The effect/unstable/rpc modules let you describe a set of remote procedures
once, as schema-backed definitions, and then derive both a typed client and
a typed server from that single description. The client method signatures, the
server handler signatures, the wire encoding, and the error channel are all
generated from the same RpcGroup — so the two ends can never drift out of
sync, and a payload or success type change is a compile error rather than a
runtime surprise.
import { Schema } from "effect"import { Rpc, RpcGroup } from "effect/unstable/rpc"
// A single shared contract. The client and server both import this group,// guaranteeing they agree on tags, payloads, results, and errors.class UserNotFound extends Schema.TaggedErrorClass<UserNotFound>()( "UserNotFound", { id: Schema.String }) {}
export class UserRpcs extends RpcGroup.make( Rpc.make("GetUser", { payload: { id: Schema.String }, // what the client sends success: Schema.Struct({ id: Schema.String, name: Schema.String }), error: UserNotFound // typed, schema-encoded failure })) {}An RPC definition is just data. Nothing is sent or handled until the group is interpreted: a client reads the schemas to encode requests and decode responses, and a server reads the same schemas to decode requests, run your handlers, and encode results. The transport (HTTP, websocket, socket, worker, or an in-memory test harness) is chosen separately and never affects the typed surface.
When to use RPC
Section titled “When to use RPC”RPC is the right tool when you control both ends and want a function-call feel across a process boundary — a backend service consumed by your own frontend, a worker thread, or a child process. It gives you typed payloads, typed errors, streaming results, and middleware without writing any serialization or routing code by hand.
If instead you need a public, REST-shaped HTTP surface with explicit paths,
methods, and status codes — for third-party consumers or OpenAPI — reach for the
HTTP API modules. RPC and HTTP API share the same Schema and
Effect foundations, so the mental model carries over.
In this section
Section titled “In this section”- Defining RPCs — declare a procedure with
Rpc.make, attach payload, success, and error schemas, model streaming results, and collect procedures into anRpcGroup. - Client and server — implement handlers with
group.toLayer, run them withRpcServer, build a typed client withRpcClient, and test the whole thing in-memory withRpcTest.
Related sections
Section titled “Related sections”RPC builds directly on concepts covered elsewhere: Schema for the wire contract, Error Management for typed failures, Services & Layers for wiring, Streaming for streaming RPCs, and the Platform / HTTP Client modules for transports.