stack-analysis
CHAPTER 52 / 90
읽기 약 2분
FUNCTION
tRPC: 타입 안전 API의 미래
핵심 개념
tRPC v11·router·procedure·미들웨어·React Query 통합 — 풀스택 TS.
본문
tRPC 셋업
pnpm add @trpc/server @trpc/client @trpc/react-query @tanstack/react-query zod서버 — Router
// server/trpc.ts
import { initTRPC, TRPCError } from '@trpc/server';
const t = initTRPC.context<Context>().create();
// 미들웨어 — 인증
const isAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.userId) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return next({ ctx: { ...ctx, userId: ctx.userId } });
});
export const router = t.router;
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(isAuthed);
// server/routers/post.ts
import { z } from 'zod';
import { router, publicProcedure, protectedProcedure } from '../trpc';
export const postRouter = router({
list: publicProcedure
.input(z.object({
limit: z.number().min(1).max(100).default(20),
cursor: z.string().optional(),
}))
.query(async ({ input, ctx }) => {
const items = await ctx.db.post.findMany({
take: input.limit + 1,
cursor: input.cursor ? { id: input.cursor } : undefined,
orderBy: { createdAt: 'desc' },
});
const nextCursor = items.length > input.limit
? items.pop()!.id : null;
return { items, nextCursor };
}),
byId: publicProcedure
.input(z.string())
.query(async ({ input, ctx }) => {
const post = await ctx.db.post.findUnique({ where: { id: input } });
if (!post) throw new TRPCError({ code: 'NOT_FOUND' });
return post;
}),
create: protectedProcedure
.input(z.object({
title: z.string().min(1).max(200),
content: z.string().min(1),
}))
.mutation(async ({ input, ctx }) => {
return ctx.db.post.create({
data: { ...input, authorId: ctx.userId },
});
}),
update: protectedProcedure
.input(z.object({
id: z.string(),
title: z.string().min(1).max(200).optional(),
content: z.string().min(1).optional(),
}))
.mutation(async ({ input, ctx }) => {
const post = await ctx.db.post.findUnique({ where: { id: input.id } });
if (!post) throw new TRPCError({ code: 'NOT_FOUND' });
if (post.authorId !== ctx.userId) {
throw new TRPCError({ code: 'FORBIDDEN' });
}
const { id, ...data } = input;
return ctx.db.post.update({ where: { id }, data });
}),
});
// 통합
export const appRouter = router({
post: postRouter,
user: userRouter,
});
export type AppRouter = typeof appRouter;클라이언트 (Next.js)
// lib/trpc.ts
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '../server';
export const trpc = createTRPCReact<AppRouter>();
// app/providers.tsx
'use client';
import { httpBatchLink } from '@trpc/client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
const trpcClient = trpc.createClient({
links: [httpBatchLink({ url: '/api/trpc' })],
});
export function Providers({ children }: { children: React.ReactNode }) {
return (
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</trpc.Provider>
);
}사용 — 완벽한 타입 안전
function PostList() {
// 자동 완성 + 타입 추론
const { data, isLoading } = trpc.post.list.useQuery({ limit: 20 });
if (isLoading) return <Skeleton />;
return (
<ul>
{data?.items.map(post => (
// post의 타입 = 서버 정의와 100% 일치
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
function CreatePost() {
const utils = trpc.useUtils();
const createMutation = trpc.post.create.useMutation({
onSuccess: () => {
// 캐시 무효화
utils.post.list.invalidate();
},
});
return (
<form onSubmit={(e) => {
e.preventDefault();
const form = new FormData(e.currentTarget);
createMutation.mutate({
title: form.get('title') as string,
content: form.get('content') as string,
});
}}>
<input name="title" />
<textarea name="content" />
<button disabled={createMutation.isPending}>
{createMutation.isPending ? '저장 중...' : '저장'}
</button>
</form>
);
}tRPC vs GraphQL vs REST
tRPC:
✅ 풀스택 TS — 100% 타입 안전
✅ 학습 곡선 낮음 (REST와 유사)
✅ 코드 생성 불필요
❌ TS 전용 (다른 언어 클라이언트 어려움)
❌ 공개 API 부적합
GraphQL:
✅ 다양한 클라이언트
✅ 선택적 페치
❌ 셋업 복잡
❌ 캐싱 어려움
REST:
✅ 표준·생태계
✅ HTTP 캐시
❌ 타입 안전 X (별도 작업)
결론:
- 사내 풀스택 TS → tRPC (강력 추천)
- 공개 API → REST + OpenAPI
- 다양한 클라이언트 → GraphQL다음 모듈
CH.53~60 "인프라 기초" — Vercel·AWS·CI/CD.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 코드의 tRPC 부분을 분석해서 실전 분석 + 개선 우선순위를 알려줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
tRPC 관련 인기 라이브러리/패턴 5개를 비교 분석해서 패턴 추출를 알려줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 프로젝트 전체에서 tRPC 최적화 가능 위치를 보고해줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 한국 백엔드 시장의 tRPC 트렌드를 솔직히 알려줘.
⭐ 이것만 기억하세요
tRPC: 타입 안전 API의 미래는 이 3가지만 확실히 잡으세요
1.tRPC = 풀스택 TS의 타입 안전 끝판왕 — 코드 생성 불필요
2.Zod 스키마 + procedure = 검증·타입·문서 통합
3.TanStack Query 통합으로 캐싱·invalidate 표준
공유하기
진행도 52 / 90