tRPC is the typed API layer between apps/server and apps/web. The contract package is intentionally thin.
Call paths
Loading diagram…
Where code lives
| What | Where |
|---|---|
| Procedures | apps/server/src/modules/<feature>/*.trpc.ts |
| Router composition | apps/server/src/modules/trpc/app.router.ts |
| Client types | packages/trpc re-exports AppRouter, createCaller |
| Browser client | apps/web → @/trpc/client |
| RSC / server actions | apps/web → trpcCaller() (in-process, no HTTP loopback) |
Data fetching patterns
Server Components / server actions
terminal
const api = await trpcCaller()
await api.posts.list()Client components
terminal
const { data } = trpc.posts.list.useQuery()Use prefetch + HydrateClient when a client boundary needs the same query on first paint.
Adding a feature
- Create
apps/server/src/modules/<feature>/ - Add
*.trpc.ts, service, repository as needed - Register router in
app.router.ts - Consume from web via
trpcortrpcCaller
Errors and auth
Procedures use shared context for session/user. Enforce authorization in procedures or policies—do not rely on “hidden” routes.
Related: Architecture