The evidence
Eight frameworks. Three machines. The bad numbers too.
The same three apps - an empty window, a notepad, and a small analytics client - built eight ways and measured on three desktops on 27 August 2026. Download size, memory at idle, in use and at its peak, CPU, time to first window and process count. Every bar, rank and charted table cell is computed from that run rather than typed in. The prose around the charts is written by hand, and it is the part to check.
Download and disk
The two figures a user can feel before the app has done anything: the bytes that come down the wire, and the bytes that stay on the disk afterwards. Both count borrowed runtime, which means every byte of engine or toolkit the artefact itself does not contain - a system webview is only the most familiar case. RayClay's own Linux notepad bar is borrowed to the tune of 72%, and its Windows bar 94%.
What the user downloads
Notepad · bytes in the artefact plus any runtime it borrows from the OS · lower is better
Linear axis 0 to 130.9× the best framework on the same machine
macOS charges no borrowed webview, and it changes everything here. WebKit is part of macOS, so a framework that renders in the system webview downloads none of it. Tauri's notepad is 262.6 MiB shipped-plus-borrowed on Linux and 0.3 MiB on macOS - the same application, with the engine already installed by Apple. Read the macOS column as "what is left to download on a machine that already has a browser engine", not as "this framework is small".
It does not follow that the macOS column is all artefact. Qt is the counterexample on this very chart: its macOS notepad bar is 65.0 MiB, of which 64.8 MiB - 99.7% - is Qt 6 runtime that sits outside the 0.18 MiB application. Only the webview is free on macOS, because only the webview ships with the OS. Read a macOS bar as "engine plus app, minus whatever Apple already installed", and if you want the app on its own, that is the next chart.
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for What the user downloads
What the user downloads - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| RayClaynative renderer | 3.2 MiB | 602.1 KiB | 11.1 MiB | 1.29× |
| Tauribrowser engine | 262.6 MiB | 284.5 KiB | 23.0 MiB | 5.60× |
| Wailsbrowser engine | 264.2 MiB | 7.7 MiB | 10.8 MiB | 13.22× |
| Flutternative renderer | 50.1 MiB | 39.0 MiB | 32.3 MiB | 18.75× |
| Qtnative renderer | 81.4 MiB | 65.0 MiB | 39.6 MiB | 27.98× |
| Bunbrowser engine | 354.4 MiB | 58.7 MiB | 111.8 MiB | 62.39× |
| Electronbrowser engine | 176.1 MiB | 114.0 MiB | 148.8 MiB | 67.83× |
| NW.jsbrowser engine | 515.0 MiB | 175.6 MiB | 237.6 MiB | 130.94× |
The application on its own
Notepad · bytes in the artefact, with no borrowed runtime counted · lower is better
Linear axis 0 to 2991.3× the best framework on the same machine
This is the size axis where RayClay does not lead, and it is here because leaving it out would have been the flattering choice. Strip the borrowed runtime and compare only the file each project actually builds, and RayClay places second of eight on Windows and third of eight on Linux and macOS. A framework that renders through a runtime the machine already has can ship almost nothing and still need all of it to run, which is why the two charts around this one count what is borrowed. Both views are true, and this is the one that flatters RayClay least.
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for The application on its own
The application on its own - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Flutternative renderer | 19.2 KiB | 39.0 MiB | 88.5 KiB | 6.06× |
| RayClaynative renderer | 898.1 KiB | 602.1 KiB | 664.0 KiB | 10.56× |
| Qtnative renderer | 165.1 KiB | 179.4 KiB | 32.1 MiB | 14.71× |
| Tauribrowser engine | 6.7 MiB | 284.5 KiB | 8.3 MiB | 37.80× |
| Wailsbrowser engine | 8.3 MiB | 7.7 MiB | 10.8 MiB | 134.67× |
| Bunbrowser engine | 88.5 MiB | 58.7 MiB | 93.9 MiB | 1196.75× |
| Electronbrowser engine | 120.9 MiB | 114.0 MiB | 94.8 MiB | 1662.61× |
| NW.jsbrowser engine | 196.7 MiB | 175.6 MiB | 220.3 MiB | 2991.31× |
What it occupies once installed
Notepad · bytes on disk after install, plus borrowed runtime · lower is better
Linear axis 0 to 203.8× the best framework on the same machine
The same macOS accounting applies here, and it is the reason Tauri looks tiny. WebKit is installed with macOS, so an app that renders in the system webview occupies none of it. Tauri's notepad installs at 262.6 MiB on Linux and 6.5 MiB on macOS - the same application. Read the macOS column as "what this app adds to a disk that already has a browser engine", not as "this framework is small".
The Windows column is not uniform either, and that is a limit of the data rather than a property of the frameworks. Tauri is credited 14.7 MiB of borrowed WebView2 on that machine; Wails, which also renders in WebView2, is credited none - its artefact and its installed-plus-borrowed figures are the same 10.8 MiB to the byte. So Wails appears near the bottom of the Windows column partly because a runtime it uses was not counted against it. Compare within a column with that in mind.
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for What it occupies once installed
What it occupies once installed - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| RayClaynative renderer | 3.2 MiB | 602.1 KiB | 11.1 MiB | 1.01× |
| Wailsbrowser engine | 264.2 MiB | 7.7 MiB | 10.8 MiB | 10.30× |
| Tauribrowser engine | 262.6 MiB | 6.5 MiB | 23.0 MiB | 12.46× |
| Flutternative renderer | 55.7 MiB | 39.0 MiB | 37.9 MiB | 15.97× |
| Qtnative renderer | 81.4 MiB | 65.0 MiB | 87.4 MiB | 28.36× |
| Bunbrowser engine | 354.9 MiB | 59.2 MiB | 112.3 MiB | 48.83× |
| Electronbrowser engine | 176.1 MiB | 275.1 MiB | 401.3 MiB | 98.63× |
| NW.jsbrowser engine | 808.1 MiB | 390.6 MiB | 543.5 MiB | 203.84× |
Memory
Resident memory in three states: an empty window doing nothing, a notepad being typed into, and the worst moment of the whole run. Qt is the framework to watch here, not Electron.
Memory, sitting there doing nothing
Empty window · resident memory at idle · lower is better
Linear axis 0 to 13.2× the best framework on the same machine
macOS memory counts something the other two machines do not.
macOS charges accelerator-backed pages inside phys_footprint;
Linux cgroup v2 and the Windows job object both exclude GPU memory. On the empty window,
73% of RayClay's 135.1 MiB macOS footprint is GPU-backed
(98.3 MiB of it). Take that share out and it reads 36.8 MiB
and moves from #7 of 8 to #2 of 7.
That is not "RayClay is lean on macOS after all". It is that the three machines are
measuring three different quantities, and each one draws the line in a different place. The Linux column runs the same way, against RayClay's opponents rather than for them. cgroup accounting covers host memory only, and RayClay reaches the screen through a real GL context, so its graphics allocations fall outside every Linux figure on this page: its Linux memory ranks are UNDER-reported beside a toolkit or a web engine. On the one machine that meters graphics memory separately, Windows, RayClay holds more of it than any framework in the set.
And the obvious way out of this has been tested and closed. If the web-engine
frameworks were simply pushing the same pixels into the window server, their own figures would
be low because somebody else was paying. We launched all eight, three times
each, and watched the window server's own memory: it moves by a couple of megabytes whichever
framework starts, and the correlation with each framework's own graphics share came out
positive where that explanation needed it strongly negative. So the pages are real and
RayClay allocates them. What the accounting difference changes is which machine's number
includes them, not whether they exist.
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for Memory, sitting there doing nothing
Memory, sitting there doing nothing - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Qtnative renderer | 11.2 MiB | 45.6 MiB | 6.4 MiB | 1.06× |
| RayClaynative renderer | 15.3 MiB | 135.1 MiB | 52.7 MiB | 3.42× |
| Flutternative renderer | 40.2 MiB | 38.0 MiB | 79.8 MiB | 3.56× |
| Tauribrowser engine | 87.3 MiB | 66.3 MiB | 143.1 MiB | 6.74× |
| Wailsbrowser engine | 81.7 MiB | 67.8 MiB | 186.3 MiB | 7.25× |
| Electronbrowser engine | 119.4 MiB | 71.7 MiB | 144.6 MiB | 7.71× |
| Bunbrowser engine | 108.9 MiB | 72.8 MiB | 384.6 MiB | 10.41× |
| NW.jsbrowser engine | 218.1 MiB | 160.1 MiB | 178.5 MiB | 13.21× |
The same macOS reading with GPU-backed pages taken out
Empty window · macOS only · idle footprint minus its accelerator share · lower is better
Linear axis 0 to 159.3 MiB
This chart does not move with the controls above: it exists on one machine only, because only macOS reports this decomposition. Two things about it run in RayClay's favour and neither is small. First, Flutter publishes no GPU share on this machine and is absent, seven frameworks rather than eight, and Flutter is the framework with the lowest total macOS footprint of the eight at 38.0 MiB - its remainder cannot exceed that, so any accelerator share above about 1.3 MiB would place it ahead of RayClay - and five of the seven shares on this chart clear that bar, while Electron and NW.js do not. Flutter's own share is the one number that would settle it and it is not measured, so read the rank here as excluding the likeliest framework to beat it. Second, Electron and NW.js report an accelerator share of only 752.0 KiB each, and this page publishes that term as unverified rather than small: it has not established where the Chromium pair's compositing surfaces are charged, and if they belong to a system process they sit outside every per-process figure here. That would understate their share, overstate their remainder, and flatter this chart's subject against them.
Show the numbers as a table for the macOS GPU decomposition
macOS, empty window, idle memory split by what backs it.
| Framework | Idle footprint | GPU-backed | GPU share | Everything else |
|---|---|---|---|---|
| Qtnative renderer | 45.6 MiB | 14.9 MiB | 33% | 30.6 MiB |
| RayClaynative renderer | 135.1 MiB | 98.3 MiB | 73% | 36.8 MiB |
| Tauribrowser engine | 66.3 MiB | 10.4 MiB | 16% | 55.9 MiB |
| Wailsbrowser engine | 67.8 MiB | 9.5 MiB | 14% | 58.2 MiB |
| Bunbrowser engine | 72.8 MiB | 12.2 MiB | 17% | 60.6 MiB |
| Electronbrowser engine | 71.7 MiB | 752.0 KiB | 1% | 71.0 MiB |
| NW.jsbrowser engine | 160.1 MiB | 752.0 KiB | 0% | 159.3 MiB |
Memory, while you use it
Notepad · resident memory during the driven active-use window · lower is better
Linear axis 0 to 14.0× the best framework on the same machine
The same macOS accounting applies to this chart, and it is not disclosed
in the macOS column itself. phys_footprint still counts
accelerator-backed pages here: 75% of RayClay's
212.0 MiB macOS reading is GPU-backed
(159.2 MiB). Take that share out, exactly as the chart above does for
the empty window, and RayClay reads 52.8 MiB and moves from
#7 of 8 to #2 of 7 - behind
Qt at 40.9 MiB. As on the empty
window, that is not "RayClay is lean on macOS after all": it is three machines measuring three
different quantities, and each one draws the line in a different place. The Linux column runs the same way, against RayClay's opponents rather than for them. cgroup accounting covers host memory only, and RayClay reaches the screen through a real GL context, so its graphics allocations fall outside every Linux figure on this page: its Linux memory ranks are UNDER-reported beside a toolkit or a web engine. On the one machine that meters graphics memory separately, Windows, RayClay holds more of it than any framework in the set.
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for Memory, while you use it
Memory, while you use it - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Qtnative renderer | 13.5 MiB | 53.9 MiB | 8.6 MiB | 1.00× |
| RayClaynative renderer | 16.0 MiB | 212.0 MiB | 63.3 MiB | 3.25× |
| Flutternative renderer | 100.3 MiB | 126.8 MiB | 110.8 MiB | 6.07× |
| Tauribrowser engine | 91.3 MiB | 171.9 MiB | 173.9 MiB | 7.57× |
| Wailsbrowser engine | 83.6 MiB | 174.3 MiB | 217.6 MiB | 7.96× |
| Electronbrowser engine | 163.0 MiB | 162.6 MiB | 205.4 MiB | 9.53× |
| Bunbrowser engine | 116.8 MiB | 180.7 MiB | 422.2 MiB | 11.24× |
| NW.jsbrowser engine | 278.9 MiB | 262.5 MiB | 233.1 MiB | 13.95× |
Memory, at its peak while you use it
Notepad · highest reading across the driven active-use window · lower is better
Linear axis 0 to 15.3× the best framework on the same machine
Two things qualify this chart, and the second one favours
RayClay. First, it has no GPU decomposition: the extract ships an accelerator share for
idle memory and for the workload, but none for peak, so the subtraction the two charts above
perform cannot be performed here. macOS phys_footprint counts
accelerator-backed pages all the same, which means the macOS peak column is not comparable with
the Linux and Windows peak columns, and no number on this page can tell you by how much.
Second, the macOS measurement window is shorter than the other two, and a
shorter window can only push a peak DOWN. A peak is the highest reading taken; observe
for less time and you get fewer chances to catch the maximum. The driven window averages
18.7 s on macOS against 20.8 s on Linux and 20.9 s on
Windows, because the macOS run spends part of its first step inside the GPU decomposition's own
vmmap call. That is a known defect of the instrument,
reproduced on two consecutive runs with both other machines
flat. So macOS peaks here are under-observed by roughly 10%, RayClay's
included, and this caveat runs in RayClay's favour rather than against it.
The window is not identical inside the macOS column either. On this app it runs
from 18.2 s to 19.8 s, a 9% spread against
about 1% on the other two machines, and RayClay's is the
second longest of the eight. More observing time is more
chances to catch a peak, so RayClay's macOS peak is better observed than most of the field it is
ranked against, and its place in this column is if anything harsher than like-for-like. The
benchmark's own report says ranks within one machine are unaffected because every framework loses the
same window; the rows this page ships say the window differs by 9%, and the rows
are what you can check.
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for Memory, at its peak while you use it
Memory, at its peak while you use it - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Qtnative renderer | 13.7 MiB | 56.1 MiB | 8.9 MiB | 1.00× |
| RayClaynative renderer | 16.2 MiB | 330.1 MiB | 66.7 MiB | 3.73× |
| Flutternative renderer | 100.8 MiB | 165.8 MiB | 115.3 MiB | 6.54× |
| Tauribrowser engine | 91.6 MiB | 189.2 MiB | 175.2 MiB | 7.61× |
| Wailsbrowser engine | 86.0 MiB | 191.6 MiB | 221.1 MiB | 8.09× |
| Electronbrowser engine | 164.1 MiB | 289.1 MiB | 207.8 MiB | 11.27× |
| Bunbrowser engine | 117.2 MiB | 198.2 MiB | 427.0 MiB | 11.29× |
| NW.jsbrowser engine | 281.2 MiB | 372.0 MiB | 235.2 MiB | 15.28× |
Memory it holds on the graphics adapter
Empty window · per-process GPU memory while the app is driven · lower is better
Linear axis 0 to 2.3× the best framework on the same machine
Two machines, and the one where RayClay is last of every framework that reports the metric. macOS has no comparable per-process counter, so this chart is Linux and Windows only and its blend is over two machines rather than three. The two disagree sharply and the disagreement is the point: on the Linux machine, with a discrete card, RayClay sits mid-field; on the Windows machine, whose adapter is integrated and whose graphics memory is therefore ordinary system RAM, RayClay holds more than any of the seven frameworks that report the metric, in all 15 of the cells the extract carries. How much more depends on the app: about twice the next framework on the empty window (1.91 to 1.99 times), and 1.34 to 1.57 times on the notepad and the analytics app. Qt appears on neither: Qt Widgets rasterises on the CPU and asks the adapter for nothing. Read the Linux column knowing the other memory charts on this page do NOT contain these bytes on that machine.
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for Memory it holds on the graphics adapter
Memory it holds on the graphics adapter - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Wailsbrowser engine | - | - | 19.0 MiB | 1.00× (1 machine) |
| Electronbrowser engine | 12.1 MiB | - | 20.3 MiB | 1.03× (2 machines) |
| Tauribrowser engine | 15.2 MiB | - | 19.0 MiB | 1.12× (2 machines) |
| NW.jsbrowser engine | 12.3 MiB | - | 27.6 MiB | 1.21× (2 machines) |
| Bunbrowser engine | 39.2 MiB | - | 20.6 MiB | 1.87× (2 machines) |
| RayClaynative renderer | 19.0 MiB | - | 54.9 MiB | 2.13× (2 machines) |
| Flutternative renderer | 49.1 MiB | - | 24.2 MiB | 2.27× (2 machines) |
| Qtnative renderer | - | - | - | - |
CPU
CPU seconds burned per wall-clock minute, shown as milliseconds. The unfocused figure is the one that decides what your laptop battery does while the app is in the background - and it is also the metric with the most caveats on this page.
CPU, while you use it
Notepad · CPU milliseconds burned per wall-clock minute during the driven active-use window · lower is better
Linear axis 0 to 8.5× the best framework on the same machine
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for CPU, while you use it
CPU, while you use it - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Qtnative renderer | 17.14 ms/min | 761.66 ms/min | 45.11 ms/min | 1.00× |
| RayClaynative renderer | 30.68 ms/min | 1026.37 ms/min | 224.77 ms/min | 2.29× |
| Tauribrowser engine | 56.85 ms/min | 1270.88 ms/min | 404.33 ms/min | 3.67× |
| Flutternative renderer | 130.16 ms/min | 961.09 ms/min | 269.38 ms/min | 3.85× |
| Wailsbrowser engine | 119.80 ms/min | 1222.07 ms/min | 359.43 ms/min | 4.47× |
| Bunbrowser engine | 364.13 ms/min | 1226.39 ms/min | 404.03 ms/min | 6.74× |
| Electronbrowser engine | 528.49 ms/min | 1340.08 ms/min | 404.49 ms/min | 7.87× |
| NW.jsbrowser engine | 535.40 ms/min | 1386.46 ms/min | 493.41 ms/min | 8.54× |
CPU, with the window not even focused
Empty window · CPU milliseconds per minute while unfocused · lower is better
Linear axis 0 to 8.1× the best framework on the same machine
The lowest readings here are below what the instrument can resolve, so they are shown as a tie and not ranked against each other. The suite records CPU per minute to a floor of 0.001 s/min, and its own report is explicit that anything under that "would be a ranking invented inside rounding noise" and that a framework which genuinely idles at zero is indistinguishable from one spending a third of a microsecond per second. On Linux both RayClay and Qt sit under that floor, so they share first place rather than RayClay beating Qt. Qt is under the floor on Windows too. "× the best on the same machine" has no value when the best is zero, so the blended bar on this chart is the macOS ratio alone - one machine of three. Nothing is floored, rounded up or dropped in the numbers themselves: the table and the per-machine rows print each reading as the extract records it, and the collapse acts on the ranking alone. In the three-machine view Linux and Windows therefore draw no bar: a ratio that does not exist cannot have a length, and a zero-length bar beside 222.87 ms/min, which is what Bun on Linux reads, would say the opposite of the number printed next to it. Those rows carry the framework's rank on that machine instead, because rank is the thing that survives a change of hardware.
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for CPU, with the window not even focused
CPU, with the window not even focused - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Flutternative renderer | 22.73 ms/min | 11.06 ms/min | 171.76 ms/min | 1.00× (1 machine) |
| Qtnative renderer | 0.53 ms/min | 11.58 ms/min | 0.00 ms/min | 1.05× (1 machine) |
| RayClaynative renderer | 0.00 ms/min | 15.82 ms/min | 78.16 ms/min | 1.43× (1 machine) |
| Bunbrowser engine | 222.87 ms/min | 49.96 ms/min | 203.02 ms/min | 4.52× (1 machine) |
| Wailsbrowser engine | 15.97 ms/min | 50.96 ms/min | 218.43 ms/min | 4.61× (1 machine) |
| Electronbrowser engine | 9.24 ms/min | 51.18 ms/min | 171.95 ms/min | 4.63× (1 machine) |
| Tauribrowser engine | 21.87 ms/min | 53.37 ms/min | 203.00 ms/min | 4.83× (1 machine) |
| NW.jsbrowser engine | 13.27 ms/min | 89.09 ms/min | 218.48 ms/min | 8.06× (1 machine) |
Getting a window on screen
Wall-clock time from launching an empty window to that window existing on screen. The measurements also carry a fixed observation window, the same length for every framework on every machine. It is a setting rather than a result, so nothing on this page charts it.
Time to the first window, from cold
Empty window · wall-clock time from launch to a window on screen · lower is better
Linear axis 0 to 6.5× the best framework on the same machine
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for Time to the first window, from cold
Time to the first window, from cold - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Tauribrowser engine | 133.2 ms | 183.9 ms | 60.1 ms | 1.22× |
| Qtnative renderer | 91.3 ms | 165.5 ms | 116.2 ms | 1.30× |
| Flutternative renderer | 412.3 ms | 146.5 ms | 148.0 ms | 2.23× |
| RayClaynative renderer | 217.5 ms | 187.3 ms | 221.7 ms | 2.24× |
| Electronbrowser engine | 307.2 ms | 252.1 ms | 163.8 ms | 2.51× |
| Bunbrowser engine | 260.5 ms | 199.7 ms | 483.9 ms | 3.15× |
| Wailsbrowser engine | 288.1 ms | 232.1 ms | 603.0 ms | 3.69× |
| NW.jsbrowser engine | 549.2 ms | 539.6 ms | 733.0 ms | 6.47× |
Process model
How many processes and threads the framework has running while an empty window sits there.
Processes it runs
Empty window · peak process count at idle · lower is better
Linear axis 0 to 8.1× the best framework on the same machine
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for Processes it runs
Processes it runs - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| Flutternative renderer | 1 | 1 | 1 | 1.00× |
| Qtnative renderer | 1 | 2 | 1 | 1.26× |
| RayClaynative renderer | 1 | 2 | 1 | 1.26× |
| Tauribrowser engine | 3 | 5 | 7 | 4.72× |
| Wailsbrowser engine | 3 | 5 | 7 | 4.72× |
| Electronbrowser engine | 8 | 4 | 4 | 5.04× |
| Bunbrowser engine | 8 | 5 | 7 | 6.54× |
| NW.jsbrowser engine | 12 | 5 | 9 | 8.14× |
Threads it runs
Empty window · peak thread count at idle · lower is better
Linear axis 0 to 21.4× the best framework on the same machine
Three different computers: each bar is a multiple of the best framework on its own machine. Compare bars within a machine, never across.
Show the numbers as a table for Threads it runs
Threads it runs - every reading, as text.
| Framework | Linux | macOS | Windows | Blended, × best on the same machine |
|---|---|---|---|---|
| RayClaynative renderer | 1 | 19 | 13 | 1.28× |
| Qtnative renderer | 7 | 19 | 9 | 2.17× |
| Flutternative renderer | 14 | 13 | 25 | 3.39× |
| Electronbrowser engine | 29 | 79 | 97 | 12.38× |
| Wailsbrowser engine | 50 | 49 | 157 | 14.87× |
| Bunbrowser engine | 67 | 52 | 156 | 16.69× |
| Tauribrowser engine | 72 | 58 | 153 | 17.61× |
| NW.jsbrowser engine | 70 | 109 | 151 | 21.43× |
Results that do not flatter us
Where RayClay loses.
A page that only shows wins is not evidence, it is advertising. These are the results in the same run where RayClay is beaten worst, taken from the same data as every bar above. Its rank on every chart is on the chart.
-
Windows GPU memory: last of 7, on an empty window
Driving the empty window on the i5-1135G7, RayClay holds 54.9 MiB of GPU memory. The next heaviest framework is NW.js at 27.6 MiB, and the rest of the field runs from 19.0 MiB up to that. In the background it is 51.2 MiB against 26.8 MiB. Roughly 2.0 times the next framework, for a window with nothing in it, on the app whose whole purpose is to show what the framework costs before your code exists. It is not confined to the empty window either: RayClay is last of the 7 in every one of the 15 Windows GPU-memory readings this run took, idle, background and in use, on the notepad and the analytics app as well as the empty window.
Two things this is not. It is not a verdict on every machine: the same measurement on the Linux machine, which has a discrete card, puts RayClay #4 of 6 rather than last. And it is not free memory on this one, because the Iris Xe is an integrated adapter, so those bytes are system RAM. Qt is absent from both columns because Qt Widgets rasterises on the CPU and asks the GPU for nothing, which is a real architectural answer to this problem and not a gap in the data.
-
macOS analytics idle memory: 8th of 8
On the analytics app at the medium data tier, RayClay idles at 244.1 MiB. Qt, on the same machine and the same app, idles at 86.5 MiB, which is 2.8 times less. That is last of eight, and on the number macOS actually reports it stays last of eight.
The honest complication, which cuts the other way: 82% of that figure is GPU-backed. Do the same subtraction this page does on the empty window above and RayClay reads 43.9 MiB - #1 of 7 among the frameworks that report a GPU share, ahead of Qt at 55.0 MiB. Both numbers are real and they are not interchangeable: one is what the operating system charges the process, the other is what is left when the accelerator's pages come out. This item stays in the losses because the first number is the one a user's activity monitor shows.
-
macOS peak memory in use: 8th of 8 on the empty window
Across the driven active-use window on the M3 Pro, RayClay's highest reading is 250.4 MiB for an empty window - rank #8 of 8. On the notepad it is 330.1 MiB, rank #7 of 8. Both figures are the same metric on the same window, and both are under-observed by roughly 10% for the reason given beside the chart - so the real numbers are, if anything, slightly worse than these.
-
Windows disk: Wails now takes the column
Installed plus borrowed on the i5-1135G7, RayClay's notepad occupies 11.1 MiB against Wails' 10.8 MiB. Disk is the column this page leans on hardest, and on this machine RayClay does not win it. It is worth being precise about why: the extract credits Wails no borrowed WebView2 on Windows while crediting Tauri 14.7 MiB of it, so part of this gap is an accounting asymmetry rather than a difference in what the two frameworks put on the disk. Part of it is not. Both readings are in the data file linked below.
-
And RayClay now leads the download column on one machine of three
On what a user downloads, RayClay is #1 of 8 on Linux at 3.2 MiB, and #2 on macOS behind Tauri at 284.5 KiB, against RayClay's 602.1 KiB. The macOS column is the one to read carefully rather than the one to quote: WebKit ships with the operating system, so a framework that renders in the system webview downloads almost nothing there, which is what puts Tauri ahead. That is a real cost a real user does not pay, and it is also the reason the number is not a statement about how much code each project wrote. Both readings are in the extract, and the chart above the fold counts borrowed runtime precisely so this is visible rather than hidden.
-
Qt beats RayClay on memory in every cell this page can compare
Idle, empty window: Qt 11.2 MiB against 15.3 MiB on Linux; 45.6 MiB against 135.1 MiB on macOS; 6.4 MiB against 52.7 MiB on Windows. In use, on the notepad: Qt 13.5 MiB against 16.0 MiB on Linux; 53.9 MiB against 212.0 MiB on macOS; 8.6 MiB against 63.3 MiB on Windows. At its peak in use, on the notepad: Qt 13.7 MiB against 16.2 MiB on Linux; 56.1 MiB against 330.1 MiB on macOS; 8.9 MiB against 66.7 MiB on Windows. Nine cells out of nine. A C++ toolkit that has been tuned for thirty years is still the one to beat on memory, and this run does not beat it.
If you are choosing a framework on idle memory alone, the honest answer from this data is Qt. The download column is where the argument lives: 3.2 MiB against 515.0 MiB is not a tuning difference.
Method and limits
How these numbers were made, and what they cannot tell you.
When each machine was measured
One run each: Linux, macOS and Windows on 27 August 2026. They are very different hardware, which is the reason this page never puts a magnitude from one beside a magnitude from another.
The three machines.
| Machine | Host | Processor, from the host name | Run id | Measured |
|---|---|---|---|---|
| Linux | linux-ryzen9-7900 | AMD Ryzen 9 7900 | 20260827T003115Z | 27 August 2026 |
| macOS | macos-m3pro | Apple M3 Pro | 20260827T003145Z | 27 August 2026 |
| Windows | windows-i5-1135g7 | Intel Core i5-1135G7 | 20260827T003211Z | 27 August 2026 |
The blend, exactly as implemented
For one metric, on one machine, take the lowest reading any framework achieved. Divide every framework's reading by it. That gives a multiple whose meaning does not depend on the hardware. Combine those multiples across the machines where the framework has a reading, using the geometric mean, because multiples compose by multiplying and an arithmetic average of them is dominated by the largest one:
ratio(f, machine) = value(f, machine) / min(value(*, machine))
blend(f) = geometric_mean(ratio(f, machine) for machine in machines if f in machine and min(machine) > 0)
The logarithmic option
A logarithmic axis makes a bar's length stop being proportional to its value, which is exactly why bar charts default to linear here. It is offered because several of these metrics span three decades and the small end is unreadable otherwise. On that scale the axis runs from one decade below the smallest reading to the decade above the largest, and it is labelled with both bounds. A reading of exactly zero cannot be placed on a logarithmic axis at all; it is drawn at zero length with its real value written beside it.
Every caveat that qualifies a chart above
- macOS counts GPU memory; Linux and Windows do not.
phys_footprintincludes accelerator-backed pages. cgroup v2 and the Windows job object exclude them. On the empty window this is 73% of RayClay's macOS figure.- macOS charges no borrowed webview - but it does charge borrowed runtime.
- WebKit ships with the OS, so every framework that renders in the system webview is credited with zero downloaded engine on that machine and only on that machine. That is a statement about webviews, not about macOS: Qt borrows 64.8 MiB there (99.7% of its 65.0 MiB bar), because Qt 6 is not part of macOS. Borrowed means any runtime the artefact does not contain, on any machine - Flutter's Linux bar is 100% borrowed with no webview in sight, and so are 72% of RayClay's.
- Every active-use repeat on all three machines was graded comparable, and this page withheld three charts on the opposite belief.
- The suite grades its own active-use window, per cell: whether the app was observed
holding focus for the whole sample, and how many repeats it could use. Each machine kept
152 of 152 repeats, with 0 recorded unfocused, across
every app and every data tier, and those counters read the same on all three. On the
Windows machine, the one this was ever in doubt for, every one of the 56
mid-window cells also reports "focus was OBSERVED and held throughout". The repeat counts are in
the extract as
w1_repeats,w1_repeats_comparableand three more; the per-cell focus verdict is in the suite's own run report for this sweep. The counts alone would not have caught the case this is about. An earlier run on this same Windows machine, taken while another window held its foreground for the whole run, reads the same 152 comparable and 0 unfocused; what separates the two is that its cells report focus lost rather than held. Until 2026-08-27 this page refused to rank the Windows column of three charts, on a caveat that read the machine's desktop rather than either record. That caveat was withdrawn in full the same day, and the charts came back, which handed RayClay three placements it had not been getting. That is the direction this page is least entitled to move in on its own authority, so the evidence is published rather than described. - The Windows CPU column is quantised to the scheduler tick.
- Each of the 8 Windows unfocused readings lands within 0.15% of a whole multiple of 15.625 ms per minute - one sixty-fourth of a second, the tick Windows accounts CPU time in. Only one of them is exactly a whole multiple - Qt's true zero; the rest are rates scaled to a per-minute window, so they land near a tick rather than on one. At that resolution the readings fall into pairs that the instrument cannot separate: Electron and Flutter on 11 ticks, Bun and Tauri on 13 ticks and NW.js and Wails on 14 ticks. Within a pair the two are separated on this page only by rounding. Read adjacent Windows CPU ranks as a tie unless the gap is at least one tick.
- All three runs failed some of their own equivalence checks, and each report says to treat its comparisons as suspect until they are resolved.
- The suite audits whether the eight apps are really doing the same work before it compares them, and on this sweep it exited non-zero on every machine: 17 on Linux, 4 on macOS and 11 on Windows. None of the failures names RayClay as the failing app, on any of the three, and that is read from the scope of every failing row rather than from a text search - "ZERO failures on ANY rig name RayClay as the failing app - verified by reading the SCOPE column of every failure row, not by counting text matches". The sentence is worth stating carefully, because it stopped being true for one sweep: macOS then flagged five frameworks, RayClay among them, for having been built before that machine's system libraries moved. Rebuilding cleared it for four of the five. It did not clear for Electron, which is measured through a downloaded runtime no rebuild here can re-fingerprint, so 3 of that machine's 4 failures are still that check, and 9 of Linux's 17 are the same check against Electron, Bun and NW.js. Every one of those is a framework this page charts. The full inventory, by machine and check, is Linux (9 build-environment, 4 pixel-liveness, 2 peer-theme, 1 conform-run, 1 empty-window-liveness), macOS (3 build-environment, 1 conform-run) and Windows (5 client-area, 3 client-area-parity, 2 analytics-locale-format, 1 conform-run) - this page does not claim to have named the ones that matter, because that judgement is the suite's and its reports carry it. Two are worth singling out because they bear directly on bars above. Tauri's Linux window paints one flat colour over the client area, which trips three separate checks across seven of those rows: it drew no content, and the surface it therefore shows is the toolkit default rather than the theme the other seven paint. One cause, seven rows. NW.js on Windows realises a window about 1.05 times the declared pixel count on the notepad and the empty window, which gives it more to draw than the frameworks it is charted against, and that one cuts in RayClay's favour.
- GPU memory is published; GPU time is not, on purpose.
- The memory an app holds on the graphics adapter is measured on Linux and Windows, and it is where RayClay does worst, so it is charted. How much GPU time each app burns is not published anywhere on this page, because it cannot be measured comparably: macOS has no per-process GPU-time counter that works, three separate readers having been tested and refused; the Linux counter returned 11 of the 24 in-use readings it should have taken, from a poll slow enough to miss a quiet app, and it is blind to the second graphics adapter in that machine. Two machines, one of them 54% empty, is not a comparison. An absent GPU-time bar means the instrument failed, never that the app used none.
- Tauri's Linux window figures are withdrawn by the people who measured them, and this page still draws them.
- On the Linux machine Tauri's WebKitGTK window paints one flat colour over the whole client area, so every figure taken with that window on screen reads artificially cheap: its Linux memory, CPU, GPU memory and time-to-window bars are all weaker evidence, biased in Tauri's favour. Its Linux disk figures are unaffected and stand. They are drawn rather than dropped deliberately: removing them would move RayClay from third to second on Linux startup and from fourth to third on Linux GPU memory, and a page should not improve its own subject's rank by deleting a competitor's inconvenient row. Read those Tauri cells as a floor, not a reading.
- Qt is not the same version on every machine.
6.10.3on Linux and Windows and6.11.1on macOS. Every other framework is pinned to one version across all three. This one is not sloppiness and it is not fixable by pinning: Qt is linked dynamically, so the Qt on the machine is the Qt the app runs, and the system version is the honest number to record.- The RayClay row is a build, not a release number.
- Every competitor names a released version; RayClay names
876ff4b9add9, the leading hex of the SHA-256 of the single header the three apps were compiled against, identical on all three machines. The site publishes RayClay as v0.8, and this says which build of it these numbers came from. Measuring a header-only library against the file itself is the only identifier that cannot drift from what was actually compiled. - One run per machine, and the launch-derived figures in it are already folded across repeats.
- The extract carries one
run_idper machine and no duplicated (os, framework, app, metric, arm) row, which is why there are no error bars here: the spread was folded away before the extract was cut rather than skipped. The suite launches each application once per repeat before starting the next, discards a warmup, and folds with a median rather than a mean, so one unlucky launch cannot carry a bar. That covers the memory, CPU and startup figures and not the disk ones, which are file sizes measured once and never launched; the extract'sproducercolumn is how you tell those two apart. What this page cannot show you either way is the spread, only its centre, because the fold happened upstream of the file it publishes. - Storage latency is measured and is deliberately not published.
- The suite exercises a CRUD workload and the extract behind this page could carry it. It does not, because RayClay does not implement that storage layer - the application developer writes it. A CRUD number would compare eight app authors, not eight frameworks, and putting it on a framework comparison would be a category error however carefully the arithmetic was done. They are dropped from the data behind this page, not merely left off the charts.
Versions
One row per framework, one column per machine, read out of the
extract. RayClay's is not a version string at all: it is the SHA-256 prefix of the exact
rayclay.h that was compiled, because a version string can
name two different builds and a hash cannot. All three machines carry the same one, which
is what makes these three runs one sweep rather than three unrelated runs.
What was built, per machine.
| Framework | Linux | macOS | Windows |
|---|---|---|---|
| RayClay | 876ff4b9add9 | 876ff4b9add9 | 876ff4b9add9 |
| Qt | 6.10.3 | 6.11.1 | 6.10.3 |
| Flutter | 3.44.9 | 3.44.9 | 3.44.9 |
| Wails | v2.14.0 | v2.14.0 | v2.14.0 |
| Tauri | 2.11.5 | 2.11.5 | 2.11.5 |
| Bun | 1.3.14 | 1.3.14 | 1.3.14 |
| Electron | 43.1.1 | 43.1.1 | 43.1.1 |
| NW.js | 0.114.0 | 0.114.0 | 0.114.0 |
Provenance, and the data itself
Every measurement charted on this page comes from one file, and you can download it: the full extract - 2,911 rows, 372.2 KiB, tab-separated, one reading per row with its machine, app, framework, metric and arm intact. It is served from this site rather than linked away, and the copy you get is written by the same build that drew the bars, from the same bytes, so it cannot drift from what you see above.
Nothing here asks you to take a chart on trust. To re-derive a bar,
filter on four columns, not three: one metric,
one app_type, one os and one
arm. The arm is the one people leave out, and leaving it out
is why a filter can come back with two rows for the same framework - a cold-start reading and
an idle one, say. Every table on this page names the arm its chart used, in the
caption. Match it and you get one value per framework.
Then divide each framework's value by the smallest in that group: that ratio is the bar. The blended bar is the geometric mean of those ratios across the machines a framework has a reading on - never an average of the raw magnitudes, which is the one operation this data does not support, and never an arithmetic average of the ratios either, which would let the single largest machine decide the bar. One chart needs a step before the division and says so beside itself: unfocused CPU has machines where the best reading is exactly zero, which makes a ratio undefined - those machines are dropped from that metric's blend rather than floored, and the chart names them.
It is a pinned extract of the RayClay competitor benchmark suite: the same rows every chart above is computed from, so any bar here can be checked against it.
Three machines, one run each, and a jester's job description: tell the king the number he did not want.
Who measured this, and on what
These numbers are ours, not an independent benchmark.
Everything here was produced by machines and scripts belonging to this project, and the eight applications being compared were written by us. It is not an industry-standard suite, it was not run by a third party, and nobody else has reproduced it. You are reading a measurement taken by the party with an interest in the result.
The apps are our idea of equivalent work rather than an agreed standard, and a framework could be disadvantaged by a decision we did not notice we were making. The suite audits itself for that and publishes the checks it fails.
The three machines
Specifications, declared rather than measured.
| Field | Linux | macOS | Windows |
|---|---|---|---|
| Manufacturer | MSI | Apple | Lenovo |
| Model | MS-7E53 | Mac15,6 | 20WM003FMX |
| RAM | 30.2 GB | 18.0 GB | 15.7 GB |
| CPU | Ryzen 9 7900 | Apple M3 Pro | i5-1135G7 |
| GPU | RTX 3090 + AMD iGPU | M3 Pro GPU | Iris Xe |
| OS | Fedora Linux 43 (Workstation) | Tahoe 26.6.1 | 11, version 25H2 (build 26200.9168) |
Please read these notes on the charts
- Rank transfers between machines. Magnitudes do not.
- Comparing frameworks on one machine is meaningful. Comparing a Linux megabyte with a macOS megabyte is not.
- The blended view averages ratios, never magnitudes.
- On each machine every framework is divided by the best one there, and those multiples are averaged. The axis reads × the best framework on the same machine, never megabytes and never milliseconds.
- One run per machine.
- A single reading per cell, with no error bar to plot. Treat a 5% gap as noise and a 10× gap as a finding.