High performanceNative-class speed isn't a tuning pass bolted on at the end — it falls out of the architecture. No virtual DOM, no diffing, no bundled runtime interpreting your component tree. And we keep the claim honest with a reproducible head-to-head benchmark against the frameworks you'd actually compare us to.
Why it's fastMost UI frameworks pay an abstraction tax at render time: a virtual DOM is built, diffed against the previous one, and the difference is reconciled into the real tree. That work scales with the size of the view, runs on every update, and competes with your app for the main thread.Idealyst doesn't have that layer. A `ui!` block expands to direct constructor calls against primitives — the macro expansion IS the runtime. There's no diff pass, no reconciler that owns your tree, no scheduler interpreting it at render time. Every abstraction collapses to a direct call.Two more multipliers compound it. Ahead-of-time compilation to native code (or WASM on web) means no JIT warmup and no interpreter. And there's no bundled runtime: no JavaScript engine, no platform VM, nothing to ship alongside your app and nothing to initialize before the first frame.
Fine-grained, not coarseReactivity is built on signals, and the dependency graph is fine-grained. A signal write updates exactly the primitives that read it — not the component, not its siblings, not a subtree. The cost of a state change is proportional to what actually depends on that state, not to the size of the screen it lives on.This is the difference that shows up under load: a list of ten thousand rows where one cell changes touches one cell. There's no "re-render the component and let the diff figure out what moved" step, because there's no diff.let count = signal!(0);
ui! {
view {
text { "This never re-runs when count changes" }
text { format!("Count: {}", count.get()) } // only THIS leaf updates
}
}
// count.set(1) writes one text node. No parent re-render,
// no sibling re-evaluation, no subtree diff. How we measurePerformance claims are easy to make and easy to fudge, so the benchmark harness is built to be hard to cheat. Every framework renders the same screen, does the same work, and is timed with the same instrumentation. The rules that keep it honest:Production builds everywhere. React runs the production esm.sh bundle calling the JSX runtime directly; Vue uses the runtime-only production build with hand-written render functions; Svelte is AOT-compiled with `dev: false`; idealyst builds release WASM with profiling features off. Dev-mode equivalents are 2–5× slower and are never reported.A strict resolution contract. The measured `setRows(n)` call must resolve by microtask, never `requestAnimationFrame` — a rAF wait would bake ~16 ms of paint delay into the number. React's update is wrapped in `flushSync` so its commit happens inside the measured window instead of being batched away afterward.Honest baselines bracket the result. Three hand-written vanilla variants mark the floor and ceiling: a static-className/CSS-variables version (what the cascade can do with no per-row JS), an honest per-element `createElement` mount, and a single bulk `innerHTML` write (the physical DOM ceiling no component framework can beat). Every framework should land somewhere on that spectrum, and you can see exactly where.
What it's compared againstThe suite ships eight variants spanning the realistic competitive set plus the vanilla baselines that bracket it. Two test suites run against them: a rebuild suite that alternates between row counts to stress mount + teardown, and a theme-toggle suite that stresses per-element style re-apply.vanilla-css-varsCascade ceiling — static classNames referencing :root variables, no per-row JS-side style work.vanilla-classesHonest per-element mount — createElement + setAttribute per row, batched through a DocumentFragment.vanilla-classes-bulkPhysical DOM ceiling — one innerHTML write hands the whole subtree to the parser. The "no JS overhead can beat this" line.react-naiveReact with inline style={...} props.react-cssvarsReact with CSS variables + static classNames.vueVue 3, :style bindings, runtime-only production build.svelteSvelte 5 with $state runes, AOT-compiled.idealyst-nativeThe framework's own web backend, release WASM.
Reproduce it yourselfWe publish the harness, not just a headline. Numbers depend on your hardware, your browser, and the day's framework releases — so rather than freeze a cherry-picked figure into this page, the whole rig is in the repo under `benchmark/`. Clone it, run one command, and measure on your own machine.# Builds every variant's bundle, then serves the runner.
benchmark/serve
# Open http://localhost:8080/ , pick a suite, click Run.
# Run with DevTools CLOSED for headline numbers;
# open the Performance tab for per-function attribution.
If you want to add your own framework to the comparison, the contract is small: build the same screen, expose `setRows(n)` honoring the microtask-resolution rule, and register the variant. The methodology, the honesty rules, and the full instructions live alongside the code.How the reactive core works →