J'ai Supprimé Mon Dernier Workflow n8n. Convex a Exécuté le Job de 30 Minutes en 80 Lignes de TypeScript.
J'ai supprimé mon dernier workflow n8n cette semaine. Il tournait depuis 8 mois sans broncher. Je l'ai supprimé parce qu'un soir, en regardant ma stack tourner, j'ai remarqué un truc débile : Convex, Infisical, NetBird, Traefik, tous passent par le même mesh VPN, tous versionnés dans le même monorepo, tout est code-reviewable.
En gros : Les éditeurs visuels avaient un vrai killer feature : « pas besoin de code ». Claude Code vient de buter cette fonctionnalité. La question maintenant, c'est de savoir si votre boulot a vraiment besoin de sortir de la couche visuelle, ou s'il s'en sort très bien dedans.
Tout sauf un service. n8n. Sa source de vérité était une SQLite locale plus 3 Google Sheets que je n'osais plus fermer.
Je n'ai rien contre n8n. Je l'ai adoré pendant 2 ans et j'ai saigné sur ses expressions JS ésotériques (quiconque a essayé {{$node["Webhook"].json["body"]["data"][0]["nested"]}} sait de quoi je parle). Mais c'est juste de la rationalité. Temps passé, service rendu, livrables vendus.

Je N'Arrivais Pas à git diff Mon Propre Workflow
Je viens de réaliser que c'était le seul service de ma stack sur lequel je ne pouvais pas faire de git diff. Pas testable. Pas facilement rejouable. Le seul truc qui m'échappait.
Et le pire, c'est que ce workflow spécifique pesait 2 633 lignes de JSON à l'export. 2 633 lignes que personne, moi y compris, ne pouvait code-review sérieusement. J'ai essayé une fois, après qu'un junior de l'équipe m'ait demandé ce que faisait un nœud spécifique et que j'ai réalisé que j'avais oublié. J'ai ouvert l'export dans VS Code, scrollé pendant 4 minutes, abandonné, et je suis retourné dans l'éditeur visuel pour trouver le nœud en cliquant partout. C'est à ce moment-là que j'ai su. Une pièce d'infrastructure que tu ne peux auditer qu'en cliquant dessus, ce n'est pas de l'infrastructure. C'est un Tamagotchi.
n8n n'est pas mal conçu. Il est conçu pour un autre boulot. Le décalage vient de moi, pas de n8n, et je le traînais depuis 8 mois sans le nommer.
Les 2 633 Lignes de JSON Que Je N'Arrivais Même Pas à Code-Review

30+ nœuds. Google Sheets utilisé comme base de données, avec des colonnes vides qui font office de machine à états, parce que c'est ce qu'on fait quand l'outil ne vous donne pas une vraie machine à états. Une boucle de polling contre une API LLM externe qui prend entre 90 secondes et 30 minutes par appel, et qui perd sa place dès que n8n redémarre. Des récepteurs webhook qui se déclenchent deux fois quand n8n est sous charge. Un setup en mode queue que j'ai passé un week-end à tuner.
Je ne m'acharne pas que sur n8n ici. Make, c'est le même problème avec un pricing pire. Paiement par opération, pas de contrôle de version, friction dès que vous avez besoin de quelque chose de sérieux. Zapier, c'est la même chose encore, facturé par tâche, chaque IF/ELSE vous coûte. n8n au moins vous laisse self-host. C'est le seul avantage architectural qu'il a sur les deux autres, et même cet avantage vient avec un setup de mode queue qui prend un week-end à tuner.
Quand je dis « je ne peux pas code-review 2 633 lignes de JSON », je suis charitable. Le staff n8n lui-même l'admet. Sur leur propre forum officiel, dans un thread intitulé N8n performance and scalability, ils écrivent : « Scaling n8n is currently not that easy » et « n8n does not scale properly yet ». Et un opérateur sur un forum communautaire a rapporté que son n8n self-hosted crashait de manière fiable sous des pics de charge de 2 000 requêtes en quelques minutes. De manière fiable. Genre, vous pouvez planifier dessus.
Ce n'est pas un hater sur Reddit. C'est n8n sur n8n.
Le Pattern TypeScript de 80 Lignes Qui a Tout Remplacé
Voici le pattern qui a remplacé les 30+ nœuds. Self-rescheduling polling avec le scheduler de Convex. État persisté à chaque étape. Si le worker crash entre deux polls, le scheduler le reprend exactement où il s'était arrêté. Pas de mode queue. Pas de SQLite à sauvegarder.
import { internalAction, internalMutation } from "./_generated/server"
import { internal } from "./_generated/api"
import { v } from "convex/values"
// Kick off a long-running external job
export const startJob = internalAction({
args: { jobId: v.string(), payload: v.any() },
handler: async (ctx, { jobId, payload }) => {
const remoteId = await callExternalLLM(payload)
await ctx.runMutation(internal.jobs.recordStart, { jobId, remoteId })
// Schedule the first poll in 30 seconds
await ctx.scheduler.runAfter(
30_000,
internal.jobs.pollStatus,
{ jobId, remoteId, attempt: 1 }
)
},
})
export const pollStatus = internalAction({
args: {
jobId: v.string(),
remoteId: v.string(),
attempt: v.number(),
},
handler: async (ctx, { jobId, remoteId, attempt }) => {
// 30 min timeout (60 polls of 30s)
if (attempt > 60) {
await ctx.runMutation(internal.jobs.markTimeout, { jobId })
await ctx.runAction(internal.jobs.notifyIncident, { jobId })
return
}
const status = await fetchRemoteStatus(remoteId)
if (status.state === "done") {
await ctx.runMutation(internal.jobs.recordResult, {
jobId,
result: status.result,
})
return
}
if (status.state === "failed") {
await ctx.runMutation(internal.jobs.recordFailure, {
jobId,
error: status.error,
})
return
}
// Still running, reschedule
await ctx.scheduler.runAfter(
30_000,
internal.jobs.pollStatus,
{ jobId, remoteId, attempt: attempt + 1 }
)
},
})
C'est tout. Environ 80 lignes une fois qu'on ajoute les mutations qui écrivent dans la table. Ça fait ce que 30 nœuds n8n faisaient, plus quelques trucs que n8n ne pourrait jamais faire proprement. Versionné avec l'app, testé avec l'app, déployé dans le même pass CI, état qui vit dans la même table Convex que le frontend lit déjà, donc l'UI voit le statut du job se mettre à jour en temps réel sans que je fasse quoi que ce soit en plus.
La raison pour laquelle ça rivalise avec le pattern step.sleep() d'Inngest, c'est que chaque appel ctx.scheduler.runAfter() persiste durablement la prochaine invocation dans le store de Convex lui-même. Si le déploiement crash en plein job, quand il revient le scheduler reprend depuis la dernière étape persistée. Je ne fake pas la durabilité avec une boucle cron en priant.
Si vous n'êtes pas sur Convex, ce pattern exact vit nativement dans Convex + Claude Code: The Ultimate Duo for Shipping SaaS at 3 AM. Et si vous êtes sur Postgres, vous avez Inngest, Trigger.dev, Temporal. Ils résolvent tous le même vrai problème : un job long, avec de l'état, qui doit survivre aux crashes. C'est le bon problème à résoudre. Ce n'est pas celui de n8n.
La plupart des tutos d'automatisation se perdent ici. Ils vous montrent comment chaîner 12 nœuds qui appellent un LLM et écrivent dans une Sheet, mais ils ne vous montrent jamais ce qui se passe quand l'appel LLM prend 14 minutes et que votre container n8n OOM à la minute 9. La réponse, c'est que vous refaites le job depuis le début et vous pleurez. Le pattern ci-dessus refait les 30 dernières secondes et continue.
La Carte d'Architecture à 4 Questions : Comment Je Choisis Vraiment

J'avais besoin d'une règle de décision qui survive aux 4 prochains lancements de framework. Voici les 4 questions que je pose maintenant.
Question 1. Job sous 30 secondes, travail de colle entre outils SaaS, pas de logique métier ?
Utilisez le visuel. Zapier, Make, n8n, tout se défend. Le coût de l'éditeur visuel est réel mais l'avantage (vous onboardez un collègue non-dev en 1 après-midi) est aussi réel. Choisir le code ici, c'est de l'over-engineering.
Question 2. Job entre 5 et 30 minutes, état durable, retries, reprise après crash ?
Code ou vous crevez. Scheduler Convex si vous êtes déjà sur Convex. Inngest, Trigger.dev ou Temporal sinon. Jamais d'éditeur visuel. Un témoignage client Trigger.dev publié sur leur landing page le dit cash à propos de Zapier et n8n : « they become complex, really slow, expensive and time-consuming to manage for large automations ». Ça colle exactement à ma propre expérience.
Question 3. CRUD plus temps réel plus frontend réactif ?
Convex direct. N'ajoutez pas Inngest par-dessus. Doubler la couche d'orchestration, c'est doubler l'état, doubler les modes de panne, doubler la danse d'auth. Le scheduler de Convex suffit pour 90% des jobs en arrière-plan dont une app SaaS a besoin. Je pense que c'est la ligne où je suis le moins sûr, honnêtement. Si vos besoins temps réel évoluent vers du multi-région avec des garanties d'ordre strictes, Convex ne sera peut-être pas la réponse dans 18 mois et vous voudrez une vraie queue. Pour l'instant ça tient.
Question 4. Pipeline de données lourdes, SQL complexe, DAGs ?
Supabase plus pg_cron, ou Airflow. Convex ne fait pas de SQL analytique ad-hoc. N'essayez pas de le forcer. C'est là que Convex arrête d'être le bon outil et que l'infrastructure en forme de Postgres commence à gagner.
C'est tout l'arbre de décision. Les 2 axes (durée et couplage) sont en dessous, mais vous n'avez pas besoin d'y penser à chaque fois. Vous demandez juste combien de temps le job vit et à quel point il touche étroitement le reste de votre code, et l'outil sort de la réponse.
La raison pour laquelle je fais plus confiance à ce framework qu'aux comparaisons outil par outil, c'est qu'il a survécu à 3 migrations de stack en 2 ans. Je suis passé de Supabase à Convex, de Vercel cron au scheduler Convex, de n8n à TypeScript, et les 4 questions n'ont pas changé une seule fois à travers tous ces mouvements. Seuls les noms des outils ont changé. Le vrai test de toute règle de décision architecturale, d'après mon expérience, c'est de savoir si elle a encore du sens 18 mois plus tard, quand la moitié des produits du slide ont une nouvelle page de pricing, un nouveau logo, ou un nouvel acquéreur. Si ça a encore du sens, gardez-le. Sinon, c'était du tool-shilling déguisé en framework, et vous pouvez le jeter avec le slide deck.
Pour Quoi J'Utiliserais Encore n8n
Je ne suis pas en croisade. Il y a des jobs où n8n gagne encore, et où Convex serait évidemment la mauvaise réponse.
Sync une Google Sheet vers un canal Slack quand une cellule change. Notification email quand une nouvelle ligne PostgreSQL apparaît. Webhook Stripe forwardé vers Discord. N'importe quel job stable, répétitif, sans logique métier, sous 30 secondes. Pour tous ceux-là, n8n bat l'écriture de TypeScript. Pas parce que n8n est génial. Parce que le job est assez petit pour que l'overhead de l'éditeur visuel soit plus petit que l'overhead du code. Le point d'équilibre est réel et n8n se trouve confortablement du bon côté pour cette classe de travail.
J'ai écrit tout un article sur pourquoi un repo open-source a transformé Claude Code en architecte n8n il y a quelques semaines. Cet article et celui-ci ne sont pas contradictoires. Claude Code rend n8n bien meilleur dans les trucs pour lesquels n8n est déjà bon. Cet article parle du moment où un job arrête d'être un de ces trucs. Le moment où votre workflow a besoin d'état durable, de retries, de replay, de code review, le moment où un junior de l'équipe regarde l'export JSON et demande « c'est normal ? » C'est là que vous partez.
(Mon pisciniste est passé hier matin pendant que je réfléchissais à tout ça, m'a demandé ce que je construisais, et j'ai dit « un truc qui surveille un autre truc pendant 30 minutes ». Il a hoché lentement et dit « ok » de la façon dont on dit « ok » à quelqu'un qui n'a clairement pas assez dormi. Il n'a pas tort. Les gosses sont rentrés de l'école une heure plus tard, le chien a volé une tortilla sur le comptoir, et j'ai oublié Convex pour le reste de l'après-midi.) 🐕
Choisissez l'Orchestration Comme de l'Infrastructure, Pas Comme un Outil
Choisir une couche d'orchestration n'est pas un choix d'outil. C'est un choix d'architecture. Les outils bougent tous les 18 mois. Convex aura un concurrent. Inngest aura un nouveau tier de pricing. n8n sortira une v3. Le framework en dessous (combien de temps le job vit et à quel point il touche étroitement le reste de votre code) ne bouge pas. C'était vrai avant n8n. Ce sera vrai après.
Et si vous lisez ça en pensant que votre workflow n8n actuel devrait passer au code, peut-être. Peut-être pas. Faites tourner les 4 questions. Si la réponse est « travail de colle entre SaaS, sous 30 secondes, pas de logique métier », restez sur n8n. Il est littéralement construit pour ça.
Supprimez un workflow cette semaine. Le plus petit que vous avez. Voyez ce que ça fait.
Sources
- "Scaling n8n is currently not that easy", réponse du staff n8n sur le forum officiel, thread N8n performance and scalability : https://community.n8n.io/t/n8n-performance-and-scalability/3150/2
- Rapport d'opérateur sur n8n self-hosted qui crash sous des pics de charge de 2 000 req, thread trying to scale N8N : https://forum.cloudron.io/topic/7174/trying-to-scale-n8n/2
- Témoignage client Trigger.dev sur la complexité de Zapier et n8n : https://trigger.dev/
- Vue d'ensemble de l'orchestration TypeScript (Temporal vs Trigger.dev vs Inngest), Matthieu Mordrel : https://medium.com/@matthieumordrel/the-ultimate-guide-to-typescript-orchestration-temporal-vs-trigger-dev-vs-inngest-and-beyond-29e1147c8f2d
Ce post peut contenir des liens d'affiliation. Si vous cliquez dessus, je pourrais gagner une petite commission, ça ne vous coûte rien, et ça m'aide à continuer à livrer des articles de qualité tous les jours pour votre plaisir de lecture.