---
title: Overview
sidebar:
  icon: layout-dashboard
description: 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](/oxide/overview) when you also want the [Vite](https://vite.dev/) or [Rsbuild](https://rsbuild.rs/) 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 `oxidejs` if 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.

## Next steps

- [Quickstart](/tacho/quickstart)
- [Router](/tacho/router)
- [HTTP](/tacho/transport/http)
- [Files](/tacho/files)
