tRPC v11 : une API full type-safe sans code generation
Zéro schéma GraphQL, zéro codegen, zéro runtime overhead — comment tRPC v11 change la façon de construire des API pour les SaaS Next.js.
Le problème avec REST et GraphQL
REST : vous écrivez votre API, puis vous écrivez les types côté client. Manuellement. À chaque changement. Et quand les types driftent... bug silencieux en production.
GraphQL : type safety, oui. Mais au prix d'un schéma à maintenir, un codegen à lancer, et un runtime qui parse chaque requête.
tRPC : vous écrivez votre API en TypeScript, et le client a les types automatiquement. Pas de codegen, pas de schéma, pas de runtime overhead.
Setup dans un SaaS Next.js
Le router tRPC
// src/server/api/routers/invoice.ts
import { z } from "zod";
import { createTRPCRouter, staffProcedure } from "~/server/api/trpc";
export const invoiceRouter = createTRPCRouter({
getAll: staffProcedure.query(async ({ ctx }) => {
return ctx.orgDb.invoice.findMany({
orderBy: { createdAt: "desc" },
include: { client: true },
});
}),
create: staffProcedure
.input(
z.object({
clientId: z.string(),
items: z.array(
z.object({
description: z.string(),
quantity: z.number().positive(),
unitPrice: z.number().positive(),
}),
),
}),
)
.mutation(async ({ ctx, input }) => {
return ctx.db.invoice.create({
data: {
organizationId: ctx.session.user.organizationId,
clientId: input.clientId,
items: { create: input.items },
},
});
}),
});Côté client — zéro configuration
"use client";
import { api } from "~/trpc/react";
export function InvoiceList() {
const { data, isLoading } = api.invoice.getAll.useQuery();
if (isLoading) return <Skeleton />;
return (
<div>
{data?.map((invoice) => (
// invoice est typé automatiquement — autocomplétion complète
<InvoiceCard key={invoice.id} invoice={invoice} />
))}
</div>
);
}Changez le type de retour côté serveur → TypeScript vous signale immédiatement les erreurs côté client. Avant même de lancer l'app.
La hiérarchie des procédures
tRPC v11 permet de chaîner des middlewares pour créer des niveaux d'accès :
// Du moins restrictif au plus restrictif
export const publicProcedure = t.procedure;
export const protectedProcedure = publicProcedure.use(enforceAuth);
export const staffProcedure = protectedProcedure.use(enforceStaffRole);
export const adminProcedure = protectedProcedure.use(enforceAdminRole);
// Permission granulaire
export const requirePermission = (perm: string) =>
staffProcedure.use(({ ctx, next }) => {
if (!hasPermission(ctx.session.user.role, perm)) {
throw new TRPCError({ code: "FORBIDDEN" });
}
return next({ ctx });
});Chaque router choisit le bon niveau. Une query publique ? publicProcedure. Un CRUD admin ? requirePermission("invoices:write").
Validation avec Zod
tRPC s'intègre nativement avec Zod pour la validation d'input :
.input(
z.object({
search: z.string().optional(),
page: z.number().int().positive().default(1),
perPage: z.number().int().min(1).max(100).default(20),
})
)Le type de input dans votre handler est inféré automatiquement depuis le schéma Zod. Un seul endroit pour la validation ET les types.
Mutations optimistes
const utils = api.useUtils();
const createInvoice = api.invoice.create.useMutation({
onSuccess: () => {
// Invalider le cache pour refetch
utils.invoice.getAll.invalidate();
},
});Pourquoi pas GraphQL ?
| Critère | tRPC | GraphQL |
|---|---|---|
| Codegen | Non | Oui |
| Runtime overhead | Zéro | Parsing + résolution |
| Setup | 10 min | 30 min + tooling |
| Type safety | Full | Full (avec codegen) |
| Cas d'usage | SaaS monorepo | API publique multi-client |
Conclusion
tRPC v11 élimine toute une catégorie de bugs — les types driftés entre client et serveur. Dans un SaaS où la vélocité compte, c'est un gain de productivité énorme.
Articles connexes
Mistral AI dans un SaaS B2B : 5 use-cases concrets en TypeScript
Intégrer une IA souveraine française dans votre SaaS — extraction de données, résumés clients, classification d'emails, génération de contenu et search sémantique.
LireTester un SaaS multi-tenant : 7 patterns Vitest indispensables
De l'isolation tenant à la vérification des permissions RBAC, les patterns de test qui rendent un SaaS B2B vraiment fiable. Avec Vitest + tRPC + Prisma.
LireArchitecture multi-tenant avec Prisma et tRPC : isolation des données garantie
Comment implémenter une isolation multi-tenant robuste dans Next.js avec Prisma $extends et tRPC — le pattern qui rend les fuites de données impossibles.
Lire