· trpc / rest / openapi

tRPC vs REST: Khi Nào Nên Bỏ OpenAPI Trong TypeScript

Dùng tRPC cho TypeScript monorepo khi type drift gây lỗi. Dùng REST + OpenAPI cho public API và consumer không phải TypeScript. Năm 2026 bạn cần cả hai.

Bởi · Cập nhật 26 tháng 5, 2026

2.587 từ · 13 phút đọc

Dùng tRPC nếu bạn kiểm soát cả hai đầu của một TypeScript monorepo và type drift đang liên tục gây ra lỗi. Dùng REST + OpenAPI nếu API của bạn có bất kỳ consumer nào không phải TypeScript — mobile app, tích hợp bên thứ ba, public endpoint. Năm 2026, câu trả lời thực tế cho hầu hết các team không phải là chọn một trong hai: chạy tRPC như internal BFF layer, dùng REST + OpenAPI ở các ranh giới tổ chức hoặc public-facing.

Bài này dành cho ai

Developer TypeScript và Node.js đang cân nhắc có nên dùng tRPC hay không. Bạn đã quen với REST + OpenAPI — schema là gì, code generator làm gì, tại sao cần cả hai. Nếu những khái niệm đó còn mới, bài này chưa phải thứ bạn cần đọc.

Vấn đề type drift

Bạn đổi tên một field ở backend. Frontend TypeScript biên dịch sạch. Lỗi lên production. Hai ngày sau bạn mới tìm ra tại sao địa chỉ người dùng không được lưu nữa.

Loại lỗi này — frontend gọi một field mà backend đã âm thầm đổi tên — chính là thứ OpenAPI + codegen cố gắng ngăn chặn. Codegen tạo typed client từ schema. Khi bạn chạy nó. Khi schema đang current. Khi CI bắt buộc chạy đó. Khi không ai tự tay sửa output đã được generate.

Đó là rất nhiều điều kiện “khi”. Trong các monorepo phát triển nhanh, schema drift là kiểu lỗi mà CI check có thể bắt vào tuần tốt, còn production incident bắt vào tuần tệ. Linter không cứu được bạn; test cũng không nếu chúng mock API. Lỗi lên production vì hai thứ tự nhận là đang đồng bộ nhưng thực ra không.

Câu trả lời của tRPC: làm cho schema drift trở nên không thể xảy ra ngay từ cấu trúc. Frontend import type trực tiếp từ backend package. Đổi tên một field ở server-side và mọi call site sẽ báo lỗi lúc compile, ngay lập tức, không cần bước codegen nào. Không có schema riêng để giữ đồng bộ vì không có schema — TypeScript chính là contract.

Đó là giá trị cốt lõi. Liệu nó có đáng không phụ thuộc vào bối cảnh cụ thể của bạn.

tRPC thực sự là gì

Không phải “type-safe RPC” theo nghĩa của gRPC hay Thrift. Không có interface definition language. Không có binary protocol. Không có wire format ngoài JSON. tRPC chạy trên HTTP thông thường và lấy type safety hoàn toàn từ structural inference của TypeScript.

Bạn định nghĩa procedure trên server:

// packages/api/src/router.ts
import { publicProcedure, router } from './trpc';
import { z } from 'zod';

export const appRouter = router({
  user: router({
    byId: publicProcedure
      .input(z.object({ id: z.string() }))
      .query(async ({ input }) => {
        return db.user.findUniqueOrThrow({ where: { id: input.id } });
      }),
    create: publicProcedure
      .input(z.object({ name: z.string(), email: z.string().email() }))
      .mutation(async ({ input }) => {
        return db.user.create({ data: input });
      }),
  }),
});

export type AppRouter = typeof appRouter;

Client import type đó — không phải implementation, chỉ type AppRouter — và có full inference ngay:

// apps/web/src/components/UserProfile.tsx
const { data } = trpc.user.byId.useQuery({ id: userId });
// data được typed từ kiểu trả về của DB — không cần annotation thủ công

const createUser = trpc.user.create.useMutation();
// input được typed; sai tên field hoặc sai kiểu = compile error

TypeScript xóa type import lúc build. Code database của bạn không bao giờ ship lên browser. Contract giữa frontend và backend là type system của TypeScript, không phải một file YAML.

Đó là end-to-end inference không cần codegen. Cái “không cần” mới quan trọng: không bao giờ bị stale, không thể bị bỏ quên, không thể bị lệch.

tRPC v11.17.0 (phát hành ngày 2026-04-28) yêu cầu TypeScript ≥ 5.7.2 và Node.js ≥ 18. v11 GA được ship ngày 21 tháng 3 năm 2025.

Nếu GraphQL cũng đang trong danh sách xem xét, xem tRPC vs GraphQL — tiêu chí đánh giá khác với REST.

Khi nào tRPC chiếm ưu thế

Full-stack TypeScript monorepo

Setup điển hình là pattern T3 Turbo: một workspace packages/api chứa tRPC router, được apps/web dùng như dev dependency. Cal.com chạy theo cách này ở quy mô lớn. Ping.gg — dự án của creator tRPC — cũng vậy. Hàng chục công ty từ YC batch 2023–2025 bắt đầu trên T3 Stack.

Lợi ích tích lũy theo thời gian. Backend team đổi tên một procedure để mô tả chính xác hơn chức năng của nó. Mọi TypeScript error trong apps/web chỉ rõ từng call site cần cập nhật. Đó là 10 phút refactor, không phải 2 ngày chạy integration test.

T3 Turbo thường kết hợp tRPC với Prisma hoặc Drizzle ở tầng database. Nếu bạn chưa chọn ORM, ORM TypeScript tốt nhất 2026 giúp thu hẹp lựa chọn.

Ràng buộc monorepo là có thật: tRPC yêu cầu chia sẻ TypeScript. Nếu bạn không ở trong một monorepo, bạn cần publish một private npm package chỉ chứa router types và bump nó mỗi khi API thay đổi. Cách đó hoạt động được — có tài liệu hướng dẫn — nhưng nó thêm overhead phối hợp, xói mòn lợi ích DX khi team vượt một ngưỡng nhất định. Hãy tính đến ràng buộc này trước khi cam kết.

Phát triển nhanh với team nhỏ

Khi số lượng consumer API của bạn là “chính chúng ta,” tRPC giảm đáng kể chi phí refactor. Di chuyển một procedure giữa các router. Thêm một input field. Thay đổi kiểu trả về. TypeScript bắt mọi call site bị ảnh hưởng ngay lập tức. Không cần cập nhật schema, không cần nhớ chạy codegen.

Hiệu năng không phải vấn đề

Benchmark trên AWS c5.xlarge (4 vCPU, 8 GB RAM, Node.js 20.x, 1.000 concurrent users qua Artillery) cho thấy tRPC chỉ thấp hơn REST HTTP/2 từ 7–9% về throughput. CRUD đơn giản: REST HTTP/2 ở 578ms trung bình so với tRPC ở 623ms. Query phức tạp: REST HTTP/2 ở 812ms so với tRPC ở 891ms.

Với browser calls, sự khác biệt không đáng kể — network latency mới là thứ quyết định, không phải serialization. Bottleneck của bạn không phải là tRPC.

Next.js App Router và Vercel

tRPC v11 hỗ trợ Next.js App Router ngay từ đầu. Prefetch procedure bên trong React Server Components; pending promise được client-side tiếp nhận và tự động hydrate TanStack Query cache.

Với Next.js app trên Vercel, tRPC procedure tích hợp vào cùng edge caching và streaming infrastructure như mọi RSC. Không cần thêm infrastructure, không cần proxy config. SSE subscription qua httpSubscriptionLink hoạt động tốt trên Vercel Edge ngay từ đầu — tRPC v11 khuyến nghị SSE thay vì WebSocket cho hầu hết các use case real-time vì SSE đơn giản hơn, tương thích CDN, và browser tự động reconnect khi mất kết nối.

Khi nào REST + OpenAPI chiếm ưu thế

Public API và external consumer

Nếu bạn publish một API để người khác gọi — mobile app, đối tác, developer bên ngoài — tRPC không phải là lựa chọn thực tế. Yêu cầu TypeScript là một ràng buộc cứng. Swift, Kotlin, Python, Go, Ruby: không ngôn ngữ nào có thể consume tRPC router một cách tự nhiên.

@trpc/openapi là cầu nối: nó generate OpenAPI 3.1 spec từ tRPC router của bạn. Nó tồn tại và hoạt động. Nhưng nó đang ở trạng thái alpha trong v11.x. Subscription bị loại trừ. API có thể thay đổi mà không báo trước. Dùng phần mềm alpha làm nền tảng cho public API contract quan trọng trong production là rủi ro hầu hết team không nên chấp nhận.

REST + OpenAPI không có ràng buộc tương đương. Một spec, client ở bất kỳ ngôn ngữ nào, tooling chuẩn ở khắp nơi. Postman, Insomnia, AI agent MCP integration, API gateway, enterprise contract negotiation: tất cả đều đọc OpenAPI natively. Service Go của đối tác không cần biết gì về setup TypeScript nội bộ của bạn.

Team đa ngôn ngữ và ranh giới tổ chức lớn

tRPC yêu cầu chia sẻ TypeScript. Các repo riêng biệt, release cadence khác nhau, hay bất kỳ service nào không phải TypeScript trong chuỗi gọi đều phá vỡ mô hình.

Các tổ chức lớn với team khác nhau, tech stack khác nhau, hoặc API contract rõ ràng giữa các team chính là nơi REST + OpenAPI phát huy giá trị, dù overhead của nó có thật. Schema là một published contract. Bạn versioning nó, gating breaking change sau một version bump, và phối hợp qua schema thay vì qua TypeScript dùng chung. Đó là bureaucracy, nhưng là loại bureaucracy có thể scale.

Tình trạng OpenAPI codegen năm 2026 đã tốt hơn đáng kể so với 2022. Speakeasy, Hey API, và Orval đều generate TypeScript client đúng kiểu và dễ dùng. OpenAPI 3.1 đồng bộ hoàn toàn với JSON Schema draft 2020-12. Khoảng cách tooling giữa DX zero-codegen của tRPC và một pipeline OpenAPI được bảo trì tốt đã thu hẹp đáng kể.

Cloudflare Workers và edge deployment

Với public-facing API trên edge, Cloudflare Workers + Hono là kiến trúc tham chiếu cho 2026 với multi-language API. Hono v4 có typed RPC riêng — khác với tRPC — cho phép TypeScript team có server-to-client type inference mà không cần dependency tRPC. Kết hợp với @hono/zod-openapi, bạn có OpenAPI 3.1 spec, edge performance, và TypeScript types, mà không yêu cầu mọi consumer phải viết TypeScript.

Một chi tiết đáng biết: tRPC v11 không có Hono adapter riêng; đường deploy được khuyến nghị trên Cloudflare Workers là tRPC Fetch adapter (docs). Nếu bạn đang đánh giá lựa chọn cho edge API mới, Hono RPC riêng xứng đáng được benchmark trực tiếp với workload của bạn trước khi chọn.

Lộ trình migrate

REST → tRPC (từng bước)

Không cần viết lại toàn bộ. Chạy tRPC song song với các REST endpoint hiện tại. Chọn một internal endpoint — user preferences, dashboard data, thứ gì đó ít rủi ro — bọc nó trong một procedure, kết nối client, và kiểm chứng DX có thực sự cải thiện trong codebase cụ thể của bạn trước khi mở rộng.

Hầu hết team dùng tRPC đều bắt đầu nhỏ, chứng minh giá trị trên một route, rồi migrate các internal endpoint trong vài tháng chứ không phải vài tuần. Câu chuyện coexistence khá gọn: tRPC và Express (hoặc Fastify) chạy trong cùng process, cùng port, dưới các path prefix khác nhau.

tRPC → REST (lối thoát)

Đường ra khỏi tRPC được tài liệu hóa rõ ràng:

  • @trpc/openapi: generate OpenAPI 3.1 từ router của bạn (alpha trong v11.x; subscription bị loại trừ). Dùng thận trọng cho internal documentation; chưa nên dựa vào làm production public contract.
  • ts-rest: contract-first REST với OpenAPI 3.1 output. Giữ TypeScript safety, đưa lại schema layer một cách tường minh — hữu ích nếu bạn muốn DX của tRPC nhưng cần một OpenAPI artifact.
  • oRPC v1.0 (tháng 12 năm 2025): DX tương thích với tRPC nhưng native OpenAPI generation, type checking nhanh hơn 1.6×, và bundle size nhỏ hơn khoảng một nửa so với tRPC. Với greenfield project năm 2026, đáng cân nhắc nghiêm túc trước khi mặc định chọn tRPC.

Không hướng nào là bẫy vĩnh viễn. Chi phí để chuyển đổi là công sức, không phải sự bất khả thi.

Kiến trúc dual-interface

Quan điểm chung năm 2026 với các team đã vượt qua giới hạn của tRPC-only: chạy tRPC như frontend BFF layer để phát triển internal nhanh, expose REST + OpenAPI ở ranh giới external hoặc inter-team. Hai router, một monorepo, phân tách rõ ràng. tRPC procedure cho web app; một Fastify hoặc Express router riêng với OpenAPI decorator cho public API. Mỗi consumer nhận interface phù hợp với nó.

Pattern này được gọi là “dual interface” trong nhiều bài viết developer năm 2025–2026, và đó là câu trả lời thực sự cho “bỏ OpenAPI đi không?” — không, nhưng bạn có thể giới hạn phạm vi của nó.

Tổng quan ecosystem 2026

MụcChi tiết
Bản ổn định mới nhấtv11.17.0 (2026-04-28)
v11 GANgày 21 tháng 3 năm 2025
TypeScript tối thiểu5.7.2
Node.js tối thiểu18
Next.js App RouterHỗ trợ đầy đủ (RSC prefetch, SSE, streaming)
TanStack QueryYêu cầu v5 (isPending, không phải isLoading)
Real-timeSSE được khuyến nghị; WebSocket có cho bidirectional
OpenAPI generation@trpc/openapi 11.x.x-alpha
Hono adapterKhông có adapter riêng trong v11; dùng tRPC Fetch adapter
Đối thủ cần theo dõioRPC v1.0 (tRPC DX + native OpenAPI, tháng 12 năm 2025)
Fix đáng chú ý trong v11.17.0React 19 proxy coercion trong createInnerProxy

Kết luận

Bối cảnhChọn
Full-stack TypeScript monorepo, internal onlytRPC
Next.js + Vercel, một frontend, một backendtRPC
Public API với external consumerREST + OpenAPI
Mobile client (iOS, Android)REST + OpenAPI
Multi-language service trong chuỗi gọiREST + OpenAPI
Tổ chức lớn, team riêng biệt, repo riêng biệtREST + OpenAPI
Edge API, Cloudflare WorkersHono RPC hoặc REST + OpenAPI
Monorepo cần OpenAPI cho một external endpointtRPC + @trpc/openapi (đánh giá rủi ro alpha)
Greenfield, đang xem xét tất cả lựa chọn năm 2026Benchmark oRPC v1.0 trước

Chọn tRPC nếu bạn kiểm soát cả frontend lẫn backend trong một TypeScript monorepo, consumer của bạn là TypeScript code nội bộ, và type drift đang gây ra lỗi thực sự.

Chọn REST + OpenAPI nếu bất kỳ ai bên ngoài TypeScript codebase của bạn gọi API, schema là một published contract, hoặc bạn cần tích hợp với tooling chuẩn.

Về “bỏ OpenAPI đi không?”: trạng thái alpha của @trpc/openapi trả lời trực tiếp câu hỏi này. Năm 2026, cầu nối đang được xây — nhưng bạn sẽ không xây production public API contract trên phần mềm alpha. Dùng tRPC ở nơi nó phù hợp rõ ràng; giữ REST + OpenAPI ở nơi contract quan trọng hơn ergonomics.

Lưu ý

Các con số hiệu năng được trích dẫn ở đây đến từ benchmark của bên thứ ba trên AWS c5.xlarge, Node.js 20.x, Artillery. Workload của bạn khác nhau; hãy chạy benchmark của riêng bạn trước khi đưa ra quyết định kiến trúc dựa trên throughput figures.

Các affiliate link đến Vercel và Cloudflare Workers trong bài này mang lại hoa hồng cho toolchew. tRPC chạy trên bất kỳ Node.js host nào. Hono chạy trên bất kỳ edge runtime nào. Các nền tảng này xuất hiện vì chúng là deployment target điển hình cho mỗi công cụ trong năm 2026, không phải vì hoa hồng ảnh hưởng đến khuyến nghị.

Tài liệu tham khảo