tRPC is a TypeScript-first RPC framework that lets you build APIs with end-to-end type safety, without writing a separate schema layer like GraphQL. No drama...
Building Production-Ready tRPC APIs: The TypeScript Alternative to Apollo Federation
tRPC is a TypeScript-first RPC framework that lets you build APIs with end-to-end type safety, without writing a separate schema layer like GraphQL. No drama. For teams already living in TypeScript, it cuts friction, reduces drift between client and server, and makes changes easier to ship. I’m Ermenildo Castro, and I’ve seen enough broken contracts to know that fewer lies in the code are a very good thing.
Key Takeaways
- tRPC shares types directly between client and server.
- It is not a drop-in replacement for Apollo Federation.
- It fits best in TypeScript-heavy teams and monorepos.
- Production use still needs auth, validation, logging, and tracing.
- For public or cross-language APIs, GraphQL may still win.
What is tRPC?
tRPC is a TypeScript remote procedure call framework that gives you end-to-end type safety without the schema-heavy work that comes with GraphQL. You write procedures in TypeScript, infer the types, and call them from the client with strong autocomplete and compiler checks. Clean. Direct. Useful.
That matters because API drift is a quiet killer. I’ve worked on systems where the frontend and backend had drifted so far apart that developers needed a map just to make a small change. That sort of mess eats time and morale. tRPC reduces that risk by making the compiler do some of the arguing for you.
It is also important to be clear about what tRPC is not. It does not do federation. It does not try to be a universal graph layer. It is not GraphQL with a fake mustache. Apollo Federation is built for composing multiple GraphQL services into one graph. tRPC is built for direct TypeScript-to-TypeScript communication. Different tools. Different jobs.
For reference, see the official tRPC documentation, the Apollo Federation docs, and the TypeScript Handbook. Those are the primary sources, not blog-flavored guesswork.
From a practical angle, tRPC is often a better fit when your backend and frontend live in the same language, especially in a monorepo. You can move faster because the type contract is the code. No duplicate schema file. No generated client dance. That simplicity can be a relief, and honestly, good engineering should spare people unnecessary sludge.
There’s a moral layer here too, subtle but real. Software is work done by people, for people. Systems that waste time and force avoidable rework are a bad use of talent. Good tools show respect for the craft and the people doing it. That’s not religious theater. It’s just responsible stewardship.
Core Benefits of tRPC in Production
The first benefit is end-to-end type safety. That is the whole pitch, and it is a good one. When the client calls a server procedure, the types are connected. Rename a field, and the compiler complains. Change an input shape, and the client sees it. The bug gets caught early, which is where bugs deserve to die.
The second benefit is lower boilerplate. Most schema-first systems make you write some version of the same thing more than once. That duplication feels harmless until it starts leaking. In one team I worked with, a simple API rename turned into a chain of codegen updates, tests, and manual fixes. It took longer than it should have. tRPC cuts out a lot of that repetitive glue.
- Less duplication between frontend and backend.
- Faster delivery for product changes.
- Cleaner reviews because contracts are easier to read.
- Better developer flow in TypeScript-first teams.
- Fewer runtime surprises from mismatched shapes.
The third benefit is speed. Not fake speed from skipping testing. Real speed from removing busywork. When I was at larger companies, the teams that stayed sharp were usually the ones that kept their API layer simple. If people spend less time translating between layers, they spend more time solving actual user problems. That is the point.
The fourth benefit is focus. tRPC suits a team that wants to build product, not maintain an elaborate schema machine. I have seen teams jump to federation too early because it sounded serious. It wasn’t serious. It was just heavy. More machinery does not always mean more maturity.
The fifth benefit is a better fit for modern frontend stacks. tRPC pairs well with React, Next.js, and TanStack Query. Caching, SSR, and mutation handling stay close to the app code. That makes the system easier to reason about, which is worth a lot when deadlines start breathing down your neck.
Finally, there is the human side. Cleaner systems are easier to teach, easier to review, and easier to hand off. That matters for team health. People do better work when they are not fighting the shape of the code every afternoon. Frankly, that should be obvious by now, but somehow it still needs saying.
Step-by-Step Implementation Guide
Production-ready does not mean fancy. It means solid. It means you can sleep at night. If you want to build a serious tRPC API, start with the basics and keep the structure boring in the good way.
- Set up a base tRPC instance with a shared context.
- Split routers by domain instead of stuffing everything into one file.
- Add input validation with Zod or another runtime schema tool.
- Wire authentication into context so permissions are checked early.
- Use middleware for common concerns like logging, auth, and rate limits.
- Return safe error shapes that help clients without leaking internals.
- Add tracing and metrics so you can see what failed and why.
- Test happy paths and failure paths before you ship.
Start with the router structure. Put related procedures together. Keep naming explicit. Avoid clever nesting unless it truly helps. I have seen more projects go sideways from sloppy structure than from missing algorithms. Small files, clear names, and obvious boundaries are not glamorous, but they save real pain.
Then validate input at the edge. Do not trust client data. Not even your own client. That is not cynicism. That is experience. Web forms, webhooks, background jobs, and admin tools all send bad data sooner or later. Runtime validation is your seat belt.
Authentication belongs in the context or middleware layer. Put user identity there and enforce permissions near the procedure. Avoid sprinkling ad hoc checks throughout the code. That turns the system into a patch quilt. I’ve seen that quilt. It’s ugly.
Observability comes next. Use structured logs and request IDs. Connect tracing if you can. OpenTelemetry is a good standard here: OpenTelemetry docs. If your service runs on AWS Lambda, the extension model can help with post-response work and telemetry flushes: AWS Lambda extensions. Measure the real behavior, not the wishful version.
For deployment, keep runtime assumptions honest. Serverless is fine. Edge-adjacent is fine. A container is fine too. What is not fine is guessing about cold starts, request timeout behavior, or log delivery. I’ve watched teams assume the platform would “just handle it.” It never does. At least not perfectly.
One more thing. Keep the code close to the people using it. If your frontend and API live in the same repo, tRPC becomes even easier to maintain. That is often where it shines most.
Comparison Table
| Feature |
tRPC |
Apollo Federation |
| Primary model |
TypeScript RPC procedures |
GraphQL federated schema |
| Type safety |
End-to-end in TypeScript |
Strong, schema-driven |
| Best for |
TS-first product teams |
Multi-team GraphQL platforms |
| Cross-language support |
Limited |
Good |
| Boilerplate |
Low |
Higher |
| Schema management |
Minimal |
Required |
| Client integration |
Very direct |
GraphQL client stack |
| Public API fit |
Weaker |
Strong |
| Federation support |
No |
Yes |
| Learning curve |
Lower for TS teams |
Higher at scale |
The table is blunt for a reason. tRPC is simpler because it solves a narrower problem. Apollo Federation is broader because it solves a coordination problem across services and teams. If your org is one frontend, one backend, one language, tRPC often wins on speed and sanity. If your company needs a shared graph across many services, Apollo Federation is the right hammer.
I have seen people choose a bigger architecture because it sounded more impressive in a meeting. That is a mistake. Tools are not medals. Pick the one that fits the work.
Common Mistakes to Avoid
The first mistake is pretending tRPC is GraphQL with a new label. It is not. It does not give you a query language or a federated schema. If you need those things, stop forcing the issue. I have seen teams burn months trying to make one tool behave like another. It’s a waste.
The second mistake is skipping runtime validation. TypeScript types are great, but they do not inspect data at runtime. Bad input still arrives. Add Zod or a similar validator at the edge. Always. This is one of those boring habits that keeps systems honest.
The third mistake is stuffing the router into one giant blob. That is lazy architecture. Split by domain. Keep admin work away from customer work. Put payment logic in one place, profile logic in another, and shared utilities in a sane location. The code should help people think, not punish them.
The fourth mistake is weak error handling. If every failure turns into “something went wrong,” you lose control of support and debugging. Map expected failures clearly. Keep sensitive details off the wire. Give clients enough information to react without exposing internals. That balance matters.
The fifth mistake is ignoring logs and traces. People get excited about compile-time safety and forget the runtime. That is short-sighted. Production failures are almost never neat. They are a trail of small problems. Observability lets you follow that trail.
The sixth mistake is thinking tRPC replaces architecture discipline. It does not. You still need boundaries, tests, deployment checks, and a basic sense of responsibility. No framework can do the work of judgment for you. It can only make some kinds of work cleaner.
Most guides say to optimize for the newest thing. I don’t buy that. Optimize for clarity, reliability, and the people who must live with the code later. That is the wiser trade.
Frequently Asked Questions
What is the main difference between tRPC and Apollo Federation?
tRPC is a TypeScript RPC framework for direct, type-safe calls inside a TypeScript stack. Apollo Federation is a GraphQL architecture for combining multiple services into one schema.
Is tRPC ready for production?
Yes, if you add validation, authentication, logging, tracing, tests, and proper deployment discipline. A toy app can get away with less. Production cannot.
Can tRPC replace GraphQL?
Sometimes. It fits well for TypeScript-first internal products and monorepos. GraphQL still fits better when you need public APIs, cross-language clients, or a federated graph.
Does tRPC work with Next.js?
Yes. tRPC is commonly used with Next.js, React, and other TypeScript-based frontend stacks.
Final Thought
If you care about clean work, tRPC deserves a serious look. I say that as Ermenildo V Castro, after years of watching teams spend too much effort on contract glue and not enough on real product value. Good tools should serve people. That is the plain truth.
tRPC is not the answer to every API problem, and that is fine. Apollo Federation has its place too. The point is not to join a team or win a tooling fight. The point is to build software that is honest, maintainable, and fair to the people who keep it alive. That includes the users, the developers, and the folks who get paged when things break.
When I look back on the best systems I have worked on, they were rarely the flashiest ones. They were the ones built with restraint, care, and enough humility to skip nonsense. That still feels like the right standard. Not loud. Just solid.