OpenTUI est-il une véritable alternative à Ink ?
OpenTUI vs Ink : comparez les performances des interfaces terminal, les limites runtime, les composants intégrés et les coûts de migration.
OpenTUI constitue une véritable alternative à Ink pour les interfaces terminal qui se redessinent en continu — sortie d’agent en streaming, visualiseurs de logs, tableaux de bord temps réel — mais ses exigences d’exécution à la pointe de la technologie et l’agitation de ses versions 0.x font d’Ink le choix par défaut le plus sûr pour un CLI que vous publiez à destination des utilisateurs Node ordinaires.
Si vous avez déjà vu votre propre tableau de bord Ink saccader sous un flux de logs soutenu, vous savez déjà pourquoi les regards se tournent ailleurs. C’est précisément cet écart qu’OpenTUI a été conçu pour combler.
Ce qui suit applique les mêmes critères aux deux bibliothèques : là où le moteur de rendu d’Ink atteint ses limites, ce que change l’architecture d’OpenTUI, à quoi ressemble la même petite interface dans chacune, quel crédit OpenTUI a gagné en production, et ce que coûte une migration en termes d’environnement d’exécution, d’écosystème et de stabilité. Le tout se conclut par une recommandation.
Points clés à retenir
- OpenTUI effectue son rendu via un cœur natif écrit en Zig, accessible depuis TypeScript par FFI, avec une mise en page flexbox Yoga et des bindings à la fois React et Solid.
- Ink limite les redessins à 30 fps par défaut, ce qui est configurable via l’option de rendu
maxFps; le chiffre de « 32 FPS » qui circule en ligne provient d’une mauvaise lecture de l’intervalle de limitation de 32 millisecondes présent dans le code source d’Ink. - Un CLI OpenTUI exige de chaque utilisateur final l’exécution de Bun 1.3+ ou de Node.js 26.4+ avec le drapeau expérimental
--experimental-ffi, ce qui constitue une contrainte de distribution, et non simplement une étape de configuration locale. - OpenTUI assure le rendu de l’interface terminal d’OpenCode en production via son réconciliateur Solid, en remplacement d’une implémentation en Go et Bubble Tea.
- La ligne 0.5.x d’OpenTUI publie plusieurs versions par mois, alors qu’Ink évolue bien plus lentement : sa dernière version majeure introduisant des ruptures, Ink 7, a relevé le socle à Node 22 et React 19.2 tout en laissant l’API des composants intacte. Ink dispose également d’un écosystème de composants communautaires bien plus vaste.
Où le moteur de rendu d’Ink atteint-il ses limites ?
Le plafond d’Ink, c’est sa limitation de rendu : par défaut, il plafonne les redessins à 30 images par seconde, et toute mise à jour d’état qui dépasse ce budget attend l’image suivante. Pour les fondamentaux d’Ink, consultez le guide précédent sur la création d’interfaces terminal avec Node.js, qui recommandait Ink en décembre 2025, avant qu’OpenTUI ne devienne une option sérieuse ; cet article est la mise à jour de ce verdict.
Cette limitation est documentée, ce n’est pas du folklore. Ink a historiquement codé en dur une limitation de 32 millisecondes autour de sa fonction de rendu, d’où provient le chiffre largement répété du « plafond de 32 FPS » : 32 est l’intervalle en millisecondes, et le taux qui en découle est un plafond de 30 images par seconde. Les versions actuelles d’Ink exposent cela via l’option de rendu maxFps, à 30 par défaut, aux côtés d’une option incrementalRendering qui restreint chaque rafraîchissement aux lignes modifiées. Le plafond est donc ajustable. Ce qui ne l’est pas, c’est l’architecture : chaque image est composée en JavaScript, comparée sous forme de chaînes de caractères, puis écrite sur stdout par la même boucle d’événements qui exécute la logique de votre application.
Pour un spinner, un formulaire ou une barre de progression, rien de tout cela n’est perceptible. Cela devient perceptible dès que la sortie devient un flux : des tokens de modèle arrivant plus vite que le budget d’image, un visualiseur de logs suivant un service chargé, un tableau de bord réaffichant de larges zones. Il y a aussi un plancher mémoire. Un processus Ink embarque l’environnement Node ainsi que le réconciliateur de React pour ce qui peut n’être que quelques lignes de sortie ; aucune mesure publique fiable de ce surcoût n’existe, donc traitez avec méfiance tout chiffre précis en mégaoctets que vous pourriez lire.
Qu’apporte OpenTUI ?
OpenTUI sort entièrement le rendu de JavaScript. Son cœur est écrit en Zig et gère nativement le tampon d’écran, le dessin et l’analyse des entrées ; TypeScript y accède par FFI, bun:ffi sur Bun ou la FFI expérimentale de Node. La mise en page reste familière : dimensionnement et positionnement passent par flexbox basé sur Yoga, le même moteur qu’utilise Ink, de sorte que flexDirection, flexGrow et compagnie se transposent directement.
Deux ajouts comptent au-delà du moteur de rendu. D’abord, les composants intégrés couvrent un terrain qu’Ink laisse aux paquets tiers : des Input et Textarea focalisables, Select, ScrollBox, une coloration syntaxique adossée à tree-sitter dans Code, une vue Diff et Markdown. Deux autres, une table de texte et un terminal embarqué, n’existent qu’en tant que renderables Core, de sorte que React et Solid ne peuvent pas y accéder comme éléments JSX. Ensuite, le choix du framework : @opentui/react et @opentui/solid sont tous deux des bindings de premier ordre, si bien que les équipes qui préfèrent une réactivité fine pour des mises à jour à haute fréquence ne sont pas enfermées dans le réconciliateur de React. Il existe également une intégration Three.js WebGPU, une curiosité pour cette comparaison, et réservée à Bun de surcroît.
À quoi ressemble la même interface dans Ink et OpenTUI ?
Le coût de migration se mesure le plus facilement en construisant deux fois la même interface : un panneau bordé, une ligne de texte, une touche qui bascule l’état, et une sortie propre. Les extraits ciblent Ink 7 et OpenTUI 0.5.x.
Ink, échafaudé avec npx create-ink-app :
import React, { useState } from "react";
import { render, Box, Text, useApp, useInput } from "ink";
function App() {
const [name, setName] = useState("world");
const { exit } = useApp();
useInput((input, key) => {
if (key.escape) exit();
if (input === "r") {
setName((prev) => (prev === "world" ? "terminal" : "world"));
}
});
return (
<Box borderStyle="round" padding={1} flexDirection="column">
<Text>Hello, {name}! Press r to toggle, Esc to quit.</Text>
</Box>
);
}
render(<App />);
OpenTUI, échafaudé avec bun create tui --template react :
import { useState } from "react";
import { createCliRenderer } from "@opentui/core";
import { createRoot, useKeyboard, useRenderer } from "@opentui/react";
function App() {
const [name, setName] = useState("world");
const renderer = useRenderer();
useKeyboard((key) => {
if (key.name === "escape") renderer.destroy();
if (key.name === "r") {
setName((prev) => (prev === "world" ? "terminal" : "world"));
}
});
return (
<box style={{ border: true, padding: 1, flexDirection: "column" }}>
<text>Hello, {name}! Press r to toggle, Esc to quit.</text>
</box>
);
}
const renderer = await createCliRenderer();
createRoot(renderer).render(<App />);
Le diff est le guide de migration. Le point d’entrée passe de l’appel render() d’Ink à createCliRenderer() depuis @opentui/core, plus createRoot(renderer).render() depuis @opentui/react. Les composants Box et Text en majuscules deviennent les intrinsèques box et text en minuscules, et les noms d’éléments composés de plus d’un mot prennent un tiret, comme dans <ascii-font>. Les useInput et useApp d’Ink correspondent à useKeyboard et renderer.destroy() chez OpenTUI. React lui-même se transpose sans changement : ink comme @opentui/react exigent React 19.2 ou plus récent, et useState fonctionne à l’identique. Les modèles de focus diffèrent davantage : Ink fournit useFocus avec un cycle Tab intégré, tandis qu’OpenTUI accorde le focus via une prop focused que vous gérez dans l’état.
Le crédit : OpenTUI assure le rendu d’OpenCode en production
OpenTUI n’est pas un projet de démonstration. Il a été développé par Anomaly, l’entreprise derrière OpenCode, et le README du projet revendique OpenCode comme un déploiement en production au service de millions de personnes. Cette charge de travail — un agent de codage diffusant en streaming des sorties de modèle, des diffs et du code coloré syntaxiquement dans un terminal interactif — est précisément celle où la limitation d’Ink se manifeste. La filiation compte aussi : l’interface d’OpenCode a été réécrite depuis Go et Bubble Tea vers OpenTUI. Une réserve pour les utilisateurs de React : le TUI d’OpenCode s’appuie sur le réconciliateur Solid, de sorte que l’éprouvement en production couvre davantage le cœur et le binding Solid que @opentui/react, lequel, contrairement à Core et Solid, n’est pas couvert par une piste Node.js en CI.
Le coût : agitation des versions, environnements d’exécution et écosystème
Les coûts se concentrent en trois points, et celui de l’environnement d’exécution est un problème de distribution, non un problème d’expérience développeur.
| Critère | Ink 7 | OpenTUI 0.5.x |
|---|---|---|
| Environnement d’exécution | Node 22+ | Bun 1.3+ ou Node 26.4+ avec --experimental-ffi, ESM uniquement |
| Rendu | JavaScript, 30 fps par défaut via maxFps | Cœur natif Zig via FFI |
| Mise en page | Flexbox Yoga | Flexbox Yoga |
| Composants intégrés | Box, Text, Static ; champs de saisie via des paquets communautaires | Input, Select, ScrollBox, Code, Diff, Markdown, et plus |
| Frameworks | React | React et Solid |
| Maturité | Versions majeures espacées de plusieurs années ; Ink 7 n’a rompu que les socles d’exécution et les événements clavier | Plusieurs versions par mois sur une ligne 0.x |
Un CLI Ink fonctionne partout où Node 22 ou plus récent fonctionne. Un CLI OpenTUI impose une exigence de pointe à chaque utilisateur final : selon la matrice de prise en charge des environnements d’exécution, cela signifie Bun 1.3.0+ ou Node.js 26.4.0+ avec le drapeau FFI expérimental, en ESM uniquement, un require CommonJS échouant purement et simplement. Pour un outil publié sur npm et installé par des inconnus, cela réduit soit votre audience, soit vous pousse vers une distribution sous forme de binaire compilé.
La stabilité est le deuxième coût. La page des releases montre les versions v0.4.4 à v0.5.8 livrées en environ six semaines. Sur une ligne 0.x, ce rythme implique de figer les versions et de surveiller le changelog. L’API d’Ink, en revanche, est restée stable à travers les années et les versions majeures. Troisièmement, l’écosystème : les paquets communautaires, recettes et réponses Stack Overflow d’Ink n’ont pas encore d’équivalent OpenTUI, même si la richesse des composants intégrés d’OpenTUI compense une partie de cet écart. Le débogage est à peu près à parité ; les deux prennent en charge React DevTools avec DEV=true, et OpenTUI ajoute une superposition console et des diagnostics de rendu.
Faut-il migrer d’Ink vers OpenTUI ?
Migrez dès maintenant si votre TUI se redessine en continu et que vous maîtrisez l’environnement d’exécution : un frontend d’agent interne, un visualiseur de logs pour votre propre équipe, tout ce qui est distribué sous forme de binaire compilé où l’exigence Bun se dissout dans la phase de build. Le cœur en Zig, les composants Code et Diff et l’option Solid sont là de véritables atouts, et OpenCode prouve l’architecture à grande échelle.
Restez sur Ink si vous publiez un CLI sur npm pour des audiences Node généralistes, si votre interface se compose de formulaires, d’invites et de progressions plutôt que de flux continus, ou si vous ne pouvez pas absorber des ruptures entre versions mineures. Les 30 fps par défaut d’Ink sont ajustables via maxFps, et son palmarès en production — Claude Code, Gemini CLI, GitHub Copilot CLI, Wrangler et Prisma, entre autres — montre jusqu’où le modèle bridé peut aller. Bubble Tea et Ratatui restent des options pour les équipes prêtes à quitter TypeScript, ce qui invalide la prémisse de départ ici.
Conclusion
OpenTUI mérite l’étiquette de « véritable alternative » sur le plan de l’architecture et des preuves en production, et Ink conserve la place par défaut sur la stabilité et la portée. La question décisive n’est pas de savoir quel moteur de rendu est le plus rapide ; c’est de savoir si vos utilisateurs peuvent exécuter votre environnement d’exécution. Prototypez votre écran le plus sollicité avec bun create tui --template react, observez-le sous un flux réel, et laissez la contrainte d’exécution, et non le benchmark, trancher.
FAQ
OpenTUI est-il réservé à Bun ou fonctionne-t-il aussi sur Node.js ?
Non, OpenTUI n'est pas réservé à Bun. Bun 1.3.0 et versions ultérieures fonctionnent, tout comme Node.js 26.4.0 et versions ultérieures, à condition que votre application soit en ESM et que vous démarriez Node avec le drapeau FFI expérimental ; importez Core via un require CommonJS et cela lève une erreur. Quelques éléments restent réservés à Bun, parmi lesquels @opentui/three et les plugins chargés à l'exécution, et la prise en charge FFI de Node est elle-même expérimentale, de sorte que Bun demeure la voie la mieux testée.
OpenTUI fonctionne-t-il sous Windows ?
Oui. Des paquets de cœur natif précompilés sont livrés pour Windows x64 et Windows arm64, ainsi que pour macOS et pour Linux en versions glibc et musl. Sous Windows, les tests propres au projet passent par Bun sur x64, tandis que sa piste d'acceptation Node.js repose sur Linux x64 ; essayez donc une version sous Windows dans un véritable terminal Windows avant de livrer, surtout si vos utilisateurs sont sur Node plutôt que sur Bun.
OpenTUI prend-il en charge React DevTools ?
Oui, malgré les affirmations contraires qui circulent en ligne. La documentation de @opentui/react décrit l'installation de react-devtools-core@7 comme dépendance de développement, l'exécution de npx react-devtools@7 et le lancement de l'application avec DEV=true pour inspecter l'arbre de composants. Ink prend en charge React DevTools de la même manière via DEV=true, de sorte que l'outillage de débogage n'est pas un facteur de différenciation significatif entre les deux bibliothèques.
Faut-il utiliser le binding React ou Solid d'OpenTUI ?
Choisissez Solid pour la voie la plus éprouvée en production : l'interface terminal d'OpenCode s'appuie sur le réconciliateur Solid, et @opentui/solid bénéficie d'une couverture CI Node.js dont @opentui/react est dépourvu. Choisissez React si votre équipe y travaille déjà ; le binding exige React 19.2.0 ou plus récent et fournit des hooks tels que useKeyboard et useTimeline. Notez que @opentui/solid fige Solid à la version 1.9.12 exactement.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k