Benchmarks
À quel point FerrFlow est-il rapide ?
Comparaison côte à côte face aux outils de release de l'écosystème JavaScript, mesurée avec hyperfine sur le même matériel, les mêmes commits et les mêmes fixtures. Les chiffres sont rafraîchis à chaque release de FerrFlow.
Dernière mise à jour : September 7, 2026, ferrflow v7.21.1, taille du binaire 8.0 MB
Médiane de 30 runs hyperfine · échelle linéaire · cache froid · FerrFlow épinglé à --jobs 1 · plus bas est meilleur. Le segment pâle au pied de chaque barre est le démarrage de l'outil — lancement du processus, boot du runtime, chargement des modules — mesuré contre une fixture plancher d'un package et un commit ; le segment coloré au-dessus est le travail. Le total est ce que vous attendez ; le découpage dit où il part.
| Tool | 1 × 100 | 10 × 100 | 50 × 500 | 100 × 1k | 50 × 5k | 200 × 10k | 50 × 300, graph |
|---|---|---|---|---|---|---|---|
| ferrflow | 7 ms | 10 ms | 25 ms | 54 ms | 193 ms | 583 ms | 22 ms |
| changesets | 536 ms | 568 ms | 626 ms | 694 ms | 678 ms | 636 ms | 638 ms |
| commit-and-tag-version | 481 ms | 489 ms | 528 ms | 600 ms | 941 ms | 1.07 s | 517 ms |
| semantic-release | 1.44 s | 1.35 s | 1.48 s | 1.58 s | 2.35 s | 2.45 s | 1.54 s |
| standard-version | 550 ms | 534 ms | 606 ms | 652 ms | 1.13 s | 1.34 s | 600 ms |
Comment on mesure
- Hyperfine avec 3 runs de warmup et 30 runs chronométrés par cellule (fixture × outil × commande). Latence médiane rapportée.
- Cache froid. FerrFlow mémoïse son analyse dans
.git/ferrflow-cache. Ce cache est vidé avant chaque run chronométré, pour que la comparaison mesure le travail lui-même — aucun des autres outils n'a d'équivalent derrière lequel s'abriter. Les chiffres à chaud sont rapportés séparément plus bas. - Peak RSS via
/usr/bin/time -vsur un run supplémentaire unique. - Les fixtures sont générées depuis FerrLabs/Fixtures avec un historique de commits conventionnels déterministe (aucune entrée instable). Le nombre de commits dans chaque label de fixture correspond au nombre de commits depuis le dernier tag de release — la fenêtre exacte que FerrFlow parcourt pour calculer un bump, pas l'historique total du dépôt.
- Toutes les commandes sont des dry runs de planification de release — chaque outil calcule la prochaine version et les notes de release sans rien écrire :
ferrflow release --dry-run,semantic-release --dry-run --no-ci,standard-version --dry-run,commit-and-tag-version --dry-run, etc. La même opération pour tous les outils, donc on compare le coût de planification, pas le coût IO de la modification réelle des fichiers. - Comparaison mono-thread. FerrFlow tourne avec
--jobs 1dans le graphe ci-dessus, il est donc mesuré comme les outils JS mono-thread. Ses chiffres parallèles réels sont rapportés séparément. - Une ligne n'est pas à armes égales, et on préfère le dire que gagner en silence. changesets planifie ses releases à partir de fichiers
.changeset/*.mdécrits à la main, jamais à partir des commits. Six de nos sept fixtures ne lui en donnent aucun : il annonce aucun package à bumper et s'arrête. Son temps suit le nombre de packages, pas l'historique : il bouge à peine sur une plage de commits 100×, parce qu'il ne les lit pas. Là où nous passons devant, l'essentiel de l'écart tient au démarrage denpxet de Node, pas à la planification de release. Retirez ce démarrage, comme le fait la décomposition du graphique ci-dessus, et sur la plus grande fixture changesets passe moins de temps à travailler que nous, parce qu'il en fait moins. Lisez cette ligne comme une différence de métier, pas comme un verdict. La fixture50 × 300, graphest le cas inverse : nous y résolvons une cascade de dépendances sur 50 packages et rattrapons les releases manquées dans l'historique, là où les autres émettent un bump et n'ont aucune notion de graphe de dépendances. - Reproductible — le pipeline complet est dans FerrLabs/Benchmarks ; les résultats sont publiés en artifacts à chaque push sur
mainet dans chaque note de release.
Mode parallèle
La comparaison épingle FerrFlow à un seul thread (--jobs 1) pour rester à armes égales avec les outils JS mono-thread. En CI réelle, il est libre d'utiliser tous les cœurs, donc ce tableau mesure ce que ça apporte réellement. Voici le même release --dry-run sur les 4 cœurs du runner de benchmark.
| Fixture | 1 thread | 4 cœurs | Accélération |
|---|---|---|---|
| Single package, 100 commits | 7 ms | 8 ms | 0.9× |
| Monorepo, 10 packages × 100 commits | 10 ms | 10 ms | 1.0× |
| Monorepo, 50 packages × 500 commits | 25 ms | 24 ms | 1.0× |
| Monorepo, 100 packages × 1k commits | 54 ms | 57 ms | 0.9× |
| Monorepo, 50 packages × 5k commits | 193 ms | 192 ms | 1.0× |
| Monorepo, 200 packages × 10k commits | 583 ms | 588 ms | 1.0× |
| Monorepo, dependency graph, 50 packages × 300 commits | 22 ms | 25 ms | 0.9× |
Cache chaud
Tous les chiffres ci-dessus sont mesurés à froid. En pratique, un dépôt bouge rarement entre deux appels à ferrflow check : FerrFlow conserve donc le résultat de sa dernière analyse dans .git/ferrflow-cache et le réutilise tant que HEAD, les tags et la config n'ont pas changé. Voici ce que coûte un second appel sur un dépôt inchangé — c'est une vraie propriété de l'outil, mais ce n'est pas une comparaison à armes égales, donc ça reste hors du graphe.
| Fixture | À froid | En cache | Accélération |
|---|---|---|---|
| Single package, 100 commits | 8 ms | 3 ms | 2.3× |
| Monorepo, 10 packages × 100 commits | 11 ms | 4 ms | 2.9× |
| Monorepo, 50 packages × 500 commits | 25 ms | 4 ms | 5.7× |
| Monorepo, 100 packages × 1k commits | 53 ms | 6 ms | 8.3× |
| Monorepo, 50 packages × 5k commits | 190 ms | 5 ms | 41.3× |
| Monorepo, 200 packages × 10k commits | 579 ms | 5 ms | 125.9× |
| Monorepo, dependency graph, 50 packages × 300 commits | 23 ms | 4 ms | 5.3× |
Empreinte d'installation
Taille sur disque après installation. release-please n'apparaît qu'ici — son runtime ne peut pas être benché hors ligne (il a besoin de l'API GitHub pour résoudre la dernière release), donc l'empreinte est la comparaison équitable qu'on peut publier.
| Outil | npm install | Binaire natif |
|---|---|---|
| ferrflow | 8.0 MB | 8.0 MB |
| changesets | 5.0 MB | — |
| commit-and-tag-version | 8.0 MB | — |
| release-please | 95.0 MB | — |
| semantic-release | 69.0 MB | — |
| standard-version | 21.0 MB | — |
Pourquoi FerrFlow affiche de plus petits chiffres
- Binaire natif. Pas de boot Node.js, pas de npm install, pas de découverte de plugins. Un
ferrflow checksur un monorepo de 50 packages se termine avant même quenode --versionait eu le temps de chauffer. - gitoxide in-process. L'énumération des tags et le parcours des commits passent par gitoxide dans le même processus. Les concurrents délèguent à
gità chaque appel ; le coût de spawn de processus domine sur les historiques denses. - Un seul outil, pas un arbre de plugins. semantic-release tire une chaîne d'analyzers, de générateurs de notes, de publishers npm et d'écrivains de changelog, chacun avec son propre coût de require(). Le pipeline de FerrFlow est une seule crate Rust.
Chiffres mis à jour à chaque release. Voir les dernières notes de release pour le tableau complet, delta baseline inclus.