Guide technique

Backends TypeScript Modernes : Hono, ElysiaJS et Ce Qui Vient Après NestJS

Comparaison honnête de Hono, ElysiaJS et NestJS par quelqu'un qui fait tourner les trois en production. DX, performance, middleware, ORM, déploiement et quand choisir chacun.

29 janvier 202616 min de lectureÉquipe d'Ingénierie Oronts

Pourquoi On Ne Démarre Plus de Nouveaux Projets avec NestJS

NestJS est un excellent framework. On a construit des systèmes enterprise dessus (Vendure tourne sur NestJS sous le capot, et on adore Vendure). Mais pour les nouveaux services backend autonomes, on est passés à Hono. Pas parce que NestJS est mauvais. Parce que Hono correspond mieux à notre façon de travailler maintenant.

Le changement s'est fait progressivement. On a démarré un nouveau service API, envisagé NestJS, et on s'est posé la question : est-ce qu'on a besoin de decorators, modules, providers et du conteneur d'injection de dépendances inspiré d'Angular pour une API de 15 endpoints ? La réponse était non. On avait besoin d'un framework HTTP rapide qui tourne sur n'importe quel runtime, avec un bon support TypeScript, et qui n'impose pas d'architecture.

Hono a répondu à ça. Ensuite on a essayé ElysiaJS sur Bun pour un service critique en performance. Le résultat était différent. Cet article est une comparaison honnête de quelqu'un qui fait tourner les trois en production.

Pour le contexte plus large sur notre approche de l'ingénierie logicielle, ce guide couvre nos principes. Pour voir comment ces frameworks s'intègrent dans l'architecture commerce, consulte notre guide Vendure en production.

Les Trois Frameworks

CaractéristiqueNestJSHonoElysiaJS
RuntimeNode.jsNode, Bun, Deno, Cloudflare Workers, Lambda, VercelBun (principalement)
ArchitectureOpinionné (modules, controllers, providers)Minimal (routes, middleware)Minimal (routes, plugins)
Sécurité des typesDecorators + validation runtimeBasé middleware, manuelValidation intégrée (typebox)
Conteneur DIIntégré (style Angular)Aucun (à toi de choisir)Aucun (plugins)
Taille du bundleLarge (~50 Mo node_modules)Minuscule (~14 Ko core)Petit (~2 Mo avec Bun)
Démarrage à froidLent (2-5s sur Lambda)Rapide (< 100ms sur Lambda)Rapide (< 50ms sur Bun)
Écosystème middlewareLarge (passport, class-validator, etc.)En croissance (auth, cors, jwt, etc.)En croissance (swagger, jwt, etc.)
Courbe d'apprentissageRaide (modules, decorators, DI, guards, pipes)Minimale (style express)Minimale (style express avec validation)
Idéal pourGrosses apps enterprise, plugins VendureAPIs multi-runtime, fonctions edge, microservicesAPIs haute performance natives Bun

Hono : Le Framework Qui Tourne Partout

Hono est un framework web construit pour l'edge. Il tourne sur Node.js, Bun, Deno, Cloudflare Workers, AWS Lambda, Vercel Edge et Fastly. Le même code se déploie sur n'importe quel runtime sans modification.

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { jwt } from 'hono/jwt';
import { logger } from 'hono/logger';

const app = new Hono();

// Middleware
app.use('*', logger());
app.use('*', cors({ origin: ['https://app.example.com'] }));
app.use('/api/*', jwt({ secret: process.env.JWT_SECRET! }));

// Routes
app.get('/api/products', async (c) => {
    const products = await productService.findAll();
    return c.json({ data: products });
});

app.get('/api/products/:id', async (c) => {
    const product = await productService.findById(c.req.param('id'));
    if (!product) return c.json({ error: 'Not found' }, 404);
    return c.json({ data: product });
});

app.post('/api/products', async (c) => {
    const body = await c.req.json();
    const product = await productService.create(body);
    return c.json({ data: product }, 201);
});

export default app;

Pourquoi On l'Aime

Portabilité runtime. On déploie le même code Hono sur Lambda (API Gateway), Bun (container) et Cloudflare Workers (edge). Aucun changement de code entre les runtimes. C'est la force unique de Hono. Aucun autre framework ne fait ça.

14 Ko de core. Les démarrages à froid sur Lambda sont sous les 100ms. Les démarrages à froid de NestJS font 2 à 5 secondes. Pour les déploiements serverless, cette différence représente toute l'expérience utilisateur.

Aucune opinion sur l'architecture. Hono te donne le routing, le middleware et le contexte. Tu décides comment structurer les services, les repositories et la logique métier. Pour les APIs petites à moyennes (5-50 endpoints), c'est exactement ce qu'il faut. Tu n'as pas besoin d'un système de modules pour 20 routes.

Intégration tRPC. On utilise Hono + tRPC pour les stacks full TypeScript. Sécurité de type de bout en bout, du serveur au client, sans GraphQL :

import { trpcServer } from '@hono/trpc-server';
import { appRouter } from './trpc/router';

app.use('/trpc/*', trpcServer({ router: appRouter }));

Où Ça Pêche

Pas de DI intégré. Pour les grosses applications avec 50+ services et des graphes de dépendances complexes, tu dois ramener ton propre conteneur DI (tsyringe, inversify) ou câbler les dépendances manuellement. C'est suffisant pour les petits services. Ça devient fastidieux pour les gros.

Écosystème middleware plus petit. NestJS a passport, class-validator, class-transformer, swagger et des centaines de packages communautaires. L'écosystème de Hono grandit mais n'en est pas encore là. Tu vas écrire plus de middleware custom.

Pas de conventions pour les grosses apps. Les modules NestJS te donnent une structure qui tient la route avec 100+ fichiers. Hono n'impose aucune structure. Pour les équipes avec des développeurs juniors, l'absence de conventions peut mener à des codebases incohérentes.

ElysiaJS : Quand la Performance Bun Compte

ElysiaJS est construit spécifiquement pour Bun. Il tire parti des APIs natives de Bun, des bindings FFI et du serveur HTTP optimisé pour atteindre des performances que les frameworks Node.js ne peuvent pas égaler.

import { Elysia, t } from 'elysia';
import { swagger } from '@elysiajs/swagger';
import { jwt } from '@elysiajs/jwt';

const app = new Elysia()
    .use(swagger())
    .use(jwt({ name: 'jwt', secret: process.env.JWT_SECRET! }))
    .get('/products', async () => {
        return productService.findAll();
    })
    .post('/products', async ({ body }) => {
        return productService.create(body);
    }, {
        body: t.Object({
            name: t.String(),
            price: t.Number({ minimum: 0 }),
            description: t.Optional(t.String()),
        }),
    })
    .listen(3000);

Pourquoi C'est Intéressant

Validation intégrée avec TypeBox. Les schémas sont définis en inline, et génèrent automatiquement la doc OpenAPI. Pas besoin de bibliothèque de validation séparée. Les types circulent du schéma au handler jusqu'à la réponse.

Performance native Bun. ElysiaJS sur Bun gère 2 à 3 fois plus de requêtes par seconde qu'Express sur Node.js pour les APIs JSON simples. Pour les workloads légers en calcul et lourds en I/O (la majorité des APIs), la différence est moins spectaculaire mais toujours mesurable.

Inférence de type de bout en bout. Le type du body de requête est inféré depuis le schéma TypeBox. Le type de la réponse est inféré depuis le handler. Le client peut utiliser Eden (le client style tRPC d'ElysiaJS) pour des appels API type-safe.

Où Ça Pêche

Bun uniquement. Si tu dois déployer sur Node.js, Lambda ou Cloudflare Workers, ElysiaJS n'est pas une option. Bun est prêt pour la production mais pas universellement supporté dans tous les environnements d'hébergement.

Écosystème plus petit. La compatibilité des packages de Bun est bonne mais pas à 100%. Certains packages Node.js utilisent des addons natifs que Bun ne supporte pas. Les drivers de base de données, les bibliothèques de traitement d'images et certains modules crypto natifs peuvent poser problème.

Moins éprouvé en production. Bun et ElysiaJS sont plus récents. La communauté est plus petite. Quand tu tombes sur un cas limite, il y a moins de réponses Stack Overflow et moins de gens qui ont résolu le même problème.

Drizzle vs Prisma vs TypeORM : La Réalité des ORM

Le choix du framework, c'est la moitié de la décision. Le choix de l'ORM, c'est l'autre moitié.

CaractéristiqueDrizzlePrismaTypeORM
Style de requêteSQL-like (explicite)API client (générée)Active Record ou Data Mapper
Sécurité des typesExcellente (inférée du schéma)Excellente (client généré)Bonne (decorators)
MigrationSQL, contrôle manuelAuto-générée, géréeAuto-générée ou manuelle
PerformanceRapide (wrapper fin sur SQL)Bonne (moteur de requêtes)Modérée (abstraction lourde)
SQL brutFirst-class (template sql``)Possible mais laborieuxPossible via query builder
Edge/ServerlessFonctionne (léger)Nécessite Prisma Accelerate pour l'edgeTrop lourd pour l'edge
Courbe d'apprentissageBasse (si tu connais le SQL)Basse (docs API excellentes)Moyenne (decorators, relations)
Taille du bundlePetit (~500 Ko)Large (~15 Mo avec moteur)Moyen (~5 Mo)
Idéal avecHono, ElysiaJSN'importe quel frameworkNestJS, Vendure

Nos Choix de Stack

Hono + Drizzle + tRPC : pour les nouvelles APIs TypeScript. Léger, rapide, type-safe de bout en bout. La syntaxe SQL-like de Drizzle nous donne un contrôle explicite sur les requêtes sans l'overhead d'abstraction de TypeORM ni l'overhead moteur de Prisma.

// Drizzle : SQL-like, explicite, type-safe
const products = await db
    .select()
    .from(productsTable)
    .where(and(
        eq(productsTable.tenantId, tenantId),
        eq(productsTable.status, 'active'),
        gt(productsTable.price, 1000),
    ))
    .orderBy(desc(productsTable.createdAt))
    .limit(20);

NestJS + TypeORM : pour les plugins Vendure et les grosses applications enterprise où le système de modules et le conteneur DI justifient leur poids. TypeORM s'intègre profondément avec NestJS et Vendure.

Prisma : quand on a besoin de migrations auto-générées et que l'équipe valorise la documentation et la DX de Prisma plutôt que le contrôle brut des requêtes.

Flexibilité de Déploiement

C'est ici que le choix du framework a le plus gros impact pratique.

Cible de déploiementNestJSHonoElysiaJS
Docker/KubernetesFonctionneFonctionneFonctionne (image Bun)
AWS LambdaDémarrages à froid lents (2-5s)Rapide (< 100ms)Non supporté
Cloudflare WorkersNon supportéFonctionne nativementNon supporté
Vercel EdgeNon supportéFonctionne nativementNon supporté
Deno DeployNon supportéFonctionne nativementNon supporté
VPS traditionnelFonctionneFonctionneFonctionne (nécessite Bun)
Bun natifPartiel (la plupart de NestJS tourne sur Bun)FonctionneNatif, optimisé

Si tu déploies uniquement sur des containers, les trois fonctionnent très bien. Si tu déploies en serverless ou sur l'edge, Hono est le seul framework qui te donne toutes les options. ElysiaJS est limité à Bun. NestJS est limité à Node (en pratique).

Pour savoir comment on déploie les services sur notre infrastructure cloud, y compris Kubernetes, Lambda et les fonctions edge, cette page détaille notre approche.

Quand NestJS Reste le Bon Choix

Malgré notre préférence pour Hono sur les nouveaux projets, NestJS est le bon choix quand :

  • Tu construis des plugins Vendure. Vendure EST NestJS. Le système de plugins, les services, les resolvers et les guards utilisent tous les patterns NestJS. Se battre contre le framework est pire que de l'utiliser.
  • Ton équipe connaît Angular. Le pattern module/provider/controller de NestJS reflète Angular. Si ton équipe vient d'Angular, la courbe d'apprentissage est quasi nulle.
  • Tu as besoin d'un large écosystème middleware. Stratégies Passport, class-validator, génération Swagger automatique, GraphQL code-first. NestJS a tout ça, intégré ou bien connecté.
  • L'application va dépasser les 100+ fichiers. Les modules NestJS fournissent une structure qui passe à l'échelle. Sans conventions (Hono, ElysiaJS), les grosses équipes ont besoin de discipline pour maintenir la cohérence.
  • Tu as besoin de support WebSocket. NestJS a des gateways WebSocket intégrées avec le même pattern de decorators. Le support WebSocket de Hono est plus manuel.

Pièges Courants

  1. Choisir Hono et reconstruire NestJS. Si tu finis par ajouter un conteneur DI, du routing basé sur des decorators, un système de modules et un pattern de guards à Hono, tu as juste construit un NestJS en moins bien. Utilise NestJS.

  2. Choisir ElysiaJS pour la production sans évaluer la compatibilité Bun. Vérifie que toutes tes dépendances fonctionnent sur Bun. Les addons natifs, certains drivers de base de données et quelques bibliothèques crypto peuvent ne pas fonctionner.

  3. Ignorer les temps de démarrage à froid en serverless. NestJS sur Lambda est inutilisable pour les APIs user-facing sans provisioned concurrency. Hono sur Lambda est assez rapide sans ça.

  4. Utiliser TypeORM avec Hono. TypeORM est conçu pour les patterns DI de NestJS. Sans DI, gérer les connexions et repositories TypeORM est laborieux. Utilise Drizzle ou Prisma avec Hono.

  5. Changer de framework prématurément. Si ton app NestJS fonctionne et que ton équipe est productive, ne passe pas à Hono juste pour être à la mode. Change quand tu as une raison concrète (déploiement serverless, fonctions edge, nouveau service autonome).

  6. Pas de couche de validation. Hono n'inclut pas de validation des requêtes. Utilise un middleware Zod ou construis le tien. Livrer une API sans validation des entrées est une vulnérabilité de sécurité.

Points Clés à Retenir

  • Hono est le framework backend TypeScript le plus polyvalent. 14 Ko de core, tourne sur tous les runtimes, démarrages à froid rapides, aucune opinion sur l'architecture. Notre choix par défaut pour les nouvelles APIs autonomes.

  • ElysiaJS offre la meilleure performance sur Bun. Validation intégrée, excellente DX, type-safe de bout en bout. Mais la limitation à Bun restreint les options de déploiement.

  • NestJS reste le bon choix pour les grosses apps enterprise et Vendure. Modules, DI, guards et un écosystème massif. La courbe d'apprentissage se rentabilise à grande échelle.

  • Drizzle est notre ORM préféré avec Hono. Syntaxe SQL-like, requêtes explicites, bundle léger. Prisma pour les équipes qui préfèrent les clients auto-générés. TypeORM pour NestJS/Vendure.

  • La cible de déploiement conditionne le choix du framework. Le serverless et l'edge nécessitent Hono. Les containers fonctionnent avec tout. Le Bun natif nécessite ElysiaJS.

  • Ne change pas de framework sans raison. Si NestJS fonctionne, continue avec. Change quand tu as besoin de serverless, d'edge, ou d'un nouveau service autonome où l'approche légère est réellement meilleure.

On construit des backends TypeScript sur les trois frameworks dans le cadre de notre pratique de développement web et de logiciel sur mesure. Si tu évalues des frameworks pour un nouveau projet, discute avec notre équipe ou demande un devis.

Sujets couverts

framework HonoElysiaJSbackend TypeScriptalternative NestJSbackend BunDrizzle ORMNode.js moderneframework serveur TypeScript

Prêt à construire des systèmes IA prêts pour la production ?

Notre équipe est spécialisée dans les systèmes IA prêts pour la production. Discutons de comment nous pouvons aider.

Démarrer une conversation