Does Express Work With tRPC?

Fully CompatibleLast verified: 2026-02-26

Express and tRPC work together seamlessly—tRPC provides the adapter pattern to mount its router directly onto Express.

Quick Facts

Compatibility
full
Setup Difficulty
Easy
Official Integration
Yes ✓
Confidence
high
Minimum Versions
Express: 4.16.0
tRPC: 10.0.0

How Express Works With tRPC

tRPC ships with an official Express adapter that makes integration trivial. You create your tRPC router and procedures as you normally would, then use the `createExpressMiddleware` function to mount it as a single route handler on your Express app. This gives you all of Express's middleware ecosystem—logging, authentication, CORS, compression—while tRPC handles your type-safe RPC layer on top.

The developer experience is excellent: you define your API procedures once in TypeScript, and the generated client types are automatically inferred from your server code. Requests go through standard HTTP (POST by default), so all existing Express middleware, rate limiting, and deployment patterns work unchanged. The single middleware mounts at a specific path (typically `/trpc`), and all your procedures tunnel through it, keeping your route definitions clean and centralized.

This is particularly well-suited for developers who want the flexibility of Express but are tired of duplicating type definitions between client and server. There are no architectural conflicts—Express handles routing and middleware, tRPC handles the RPC protocol and type safety.

Best Use Cases

Building a full-stack TypeScript app where client and server share types automatically, eliminating API contract drift
Migrating from REST to a type-safe RPC layer without rewriting your entire Express setup
SaaS applications needing Express's mature middleware ecosystem (auth, logging, monitoring) combined with tRPC's zero-codegen approach
Monorepos with shared packages where TypeScript types naturally flow from server procedures to frontend clients

Quick Setup

bash
npm install express @trpc/server @trpc/client zod
typescript
import express from 'express';
import { initTRPC } from '@trpc/server';
import { createExpressMiddleware } from '@trpc/server/adapters/express';
import { z } from 'zod';

const t = initTRPC.create();

const router = t.router({
  hello: t.procedure
    .input(z.object({ name: z.string() }))
    .query(({ input }) => ({
      message: `Hello, ${input.name}!`,
    })),
  addPost: t.procedure
    .input(z.object({ title: z.string() }))
    .mutation(({ input }) => ({
      id: 1,
      title: input.title,
    })),
});

export type AppRouter = typeof router;

const app = express();

app.use(
  '/trpc',
  createExpressMiddleware({
    router,
    createContext: () => ({}),
  })
);

app.listen(3000, () => console.log('Server running on :3000'));

Known Issues & Gotchas

warning

File upload handling requires additional setup since tRPC doesn't natively handle multipart/form-data

Fix: Use `express.json()` and `express.urlencoded()` middleware before tRPC, or handle file uploads on separate Express routes outside tRPC

info

CORS headers must be set on the Express app itself, not within tRPC

Fix: Apply `cors()` middleware to your Express app before mounting the tRPC middleware

warning

tRPC batch requests can bypass standard Express rate-limiting if not configured at the middleware level

Fix: Apply rate limiting middleware to the entire Express app or specifically to the tRPC route

Alternatives

  • Fastify + tRPC: Similar zero-codegen RPC model with better async/await support and performance
  • Next.js API Routes + tRPC: Built-in framework with file-based routing and built-in tRPC support via `next-trpc`
  • Hono + tRPC: Lightweight edge-first alternative with smaller bundle size, good for serverless

Resources

Related Compatibility Guides

Explore more compatibility guides