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 |
Règle simple
Si votre API est consommée uniquement par votre frontend (SaaS), prenez tRPC. Si vous avez des clients externes (mobile tiers, partenaires), prenez GraphQL.
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.
Pour aller plus loin
Articles connexes
Mistral AI dans un SaaS B2B : 5 use-cases concrets en TypeScript
Intégrer une IA française dans votre SaaS : extraction de données, résumés, classification d'emails, génération de contenu et recherche 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.
LireMulti-tenant avec Prisma et tRPC : isoler les données par organisation
Isoler les données de chaque organisation dans Next.js avec Prisma $extends et tRPC : ce que le filtre automatique couvre, et ce qui reste explicite.
LirePrêt à lancer ton SaaS ?
HeartCo Starter inclut tout ce dont tu as besoin : auth, paiements, IA, mobile, sécurité auditée. À partir de 199 €.