| Measure | Flow | Node-RED | Ratio |
| Image size | 45.64 MB | 717 MB | 16× |
| Throughput | 3,460 req/s | 1,290 req/s | 2.7× |
| Latency p50 | 1.03 ms | 4.61 ms | 4.5× |
| Latency p99 | 16.72 ms | 23.14 ms | 1.4× |
| Cold start | 2.1 to 2.3 s | 4.6 to 5.5 s | ~2.3× |
Three things that table does not say.
- Cold start includes roughly two seconds of container start that both runtimes pay, so the
real gap between the two programs is smaller than that row implies.
- The throughput figure includes the whole HTTP stack, on purpose, since that is the only
surface both present identically. It is not a measurement of either scheduler in isolation, and it should
not be quoted as one.
- The p99 gap is far narrower than the p50 gap, for a reason that flatters nobody. Under
saturation both runtimes queue, queueing dominates the tail, and the median is the only column where
per-request cost actually shows up.
Two more, so nobody has to find them. The throughput, latency and cold start rows are from the run on
2026-08-08, on an earlier build of Flow, so don't divide them by the newer absolute numbers above. The image
row is the 2.8.0 image, built from the release tree (45.64 MB, measured as above), against the Node-RED image from that run. When I ran it, Flow was 25.1 MB
and the gap was 29×, and Flow has grown since, with the plant nodes, tracing, the SQLite state store, the HotLoop, MCP and plugin work of 2.3.0, and FlowLab since.
Memory isn't in this table, on purpose. Those numbers came off podman stats, which reports what
the kernel charges the container, not what the process holds, and nobody could reproduce them, me included.
Flow's own memory is in the absolute numbers above, and there is no Node-RED column next to it, because
nobody has measured Node-RED the same way yet. A ratio across two methods is exactly the mistake that got the
old numbers pulled.