The same three jobs, three engines

A 10 000-row table, a search filter and an optimistic PATCH, implemented in Aegis 0.7.0, Alpine 3.14 and Vue 3.5. Nothing is precomputed: press Run and the numbers come from your browser, on your machine, medians of three rounds. Alpine and Vue load from cdnjs in their production builds.

Not run yet. The table below fills in as each engine finishes.
JobAegisAlpineVue
Create N rows–––
Filter by “ea” (about a third of the rows)–––
Clear the filter–––
Optimistic PATCH of one row (UI updated before the request)–––
Remove all rows–––
Lines of code for the component–––
Library on the wire, gzip30 KB islands + templates (108 KB full file as served)15 KB34 KB

Milliseconds from the state change to the DOM being updated, layout forced. Each engine gets the same data, the same table markup and its own idiomatic code: signals and a keyed list(), x-data with x-for, reactive data with v-for :key. The PATCH job measures only the client side: the row changes first, a mock request follows. Numbers under a millisecond are noise; what to look at is the shape, and whether a job scales with the number of rows or with the number of changed rows.

The stages

Aegis
Alpine
Vue

The three implementations

Exactly the code that ran, taken from the page's own script. Each exposes create, filter, patch and tick (how the engine flushes) to the harness.

Aegis

Alpine

Vue

Not on this page: React. A React table needs a bundler and either a store or re-renders per change, which makes the comparison about setup rather than the engine; the playground shows the same todo list in React, Vue and Aegis side by side instead. The engine's own numbers on a 1 000-row table are in bench.html and in the benchmarks page.