Overview
Define procedures once, then call them in the same process or from another machine - the types are the same.
tacho is RPC you never write a client for. Define a router. Call it in the same process. Serve it over HTTP, a stream, or a WebSocket. The router type is the client.
oxidejs server actions ride on tacho. You can also use tacho with no bundler plugin.
Choosing an RPC layer
Choose tacho when you want typed procedures that work the same locally and over the network. Use oxidejs when you also want the Vite or Rsbuild build. Stay on another RPC stack if you already depend on that ecosystem.
- Choose tacho if you want JSON-RPC, a schema you already use, and a typed client.
- Choose
oxidejsif you want actions plus a server bundle. - Wrap the HTTP handler yourself if you need CORS or a custom path.
What you get
- One type - the router type is the client. Nested paths read like
user.get. - JSON-RPC - batch, notifications, reserved method names. Works with any JSON-RPC client.
- Any runtime - the handler takes a request and returns a response.
- Your schema - Zod, Valibot, ArkType, or anything else that speaks Standard Schema.
- Middleware - run code around a procedure. Add a user, skip the handler, or change the result.
- Streams, files, WebSocket - yield values as they happen. Send or return a file. Share one socket.
Bad input is rejected. Bad output is an internal error. CORS is not built in.