What Bones

Fastify and tRPC

A fast, plain HTTP server underneath, and typed procedures on top.

Why tRPC

tRPC gives end-to-end types between the backend and the apps with no schema file and no code generation. You write a function on the server and call it from the client, typed.

The trade-off: tRPC is TypeScript-only. A Python client or a public API would need something else. The plan for that, if it comes up, is trpc-to-openapi for tRPC and Better Auth's OpenAPI plugin for auth.

Why Fastify

Fastify handles everything tRPC doesn't:

  • Auth. Better Auth's handler is mounted at /api/auth/*.
  • Redirects and callbacks. The desktop sign-in bridge and OAuth callbacks are plain routes.
  • Streaming. The chatbot streams replies from POST /chatbot/stream as newline-delimited JSON.
  • Hooks. A global onResponse hook writes the request log.

Where the checks live

Permissions are checked in tRPC middleware, not Fastify hooks. Every procedure builder — protectedProcedure, requirePermission, and the rest — descends from one logged base, so a new procedure gets logging and auth for free.

Used in