Build1 distinct publisher3 min readUpdated
The one-line Express 5 replacement claims 2x to 20x faster routing. Its author is explicit that the spread lands on thousand-route tables, not on hello world.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Fulmine.js is presented as a drop-in replacement for Express 5 that runs on uWebSockets.js instead of node:http, swapped in by changing one require line [1][2]. The claim attached to it is that routing gets between 2x and 20x faster [3], and the interesting part is the shape of the curve rather than the number: the author says the advantage grows with the size of the application instead of shrinking [8]. The mechanism is not exotic. Express's router walks a list of layers in order until one matches, so every route you register adds work to every request [4]. On a small application nobody notices; on an application with a thousand routes, which is what the author describes as a generated API layer or a multi-tenant backend, it becomes the main cost of the request, and it is paid before your own code runs at all [5]. Fulmine registers routes on uWebSockets.js's own router, which matches the path in C++ and hands over a chain worked out at startup, so nothing is scanned per request [6]. That framing is also the honest limit on the headline figure. The 2x to 20x range is scoped to routing [3], and the author states the gap is smallest on hello world and largest on the big route tables [8]. If your service has forty routes, you are buying the small end of that spread, not the large one. The numbers are the project's own. They are given as spreads over the last nine CI runs, landing on three different runner shapes, all on Node 26, with the author noting that a single figure from a single run would not be honest [7]. He also concedes that numbers produced by a project about itself deserve suspicion and points at HttpArena, run on other people's rigs under their own rules [9]. The more consequential piece is the zero-JavaScript path. A handler simple enough to be read at registration time is compiled into a uWS response written once at startup and answered without entering JavaScript at all [10]. The conditions are strict: nothing in front of the route, and a single handler that only calls res.status, res.set, res.type, res.send, res.json, res.sendStatus or res.end with literal arguments [11]. The author's argument is that real services are full of exactly that: health and readiness probes, config endpoints, feature flags, robots.txt, .well-known files, static manifests, and that in a Kubernetes cluster the probes alone are a large share of requests and pure framework overhead [12]. You are not left guessing. `npx fulmine.js profile` reports the verdict per route, and the sample output shows 3 routes, 2 answered by uWS itself, 1 of them without running any JavaScript [13] - one route in three on the fully compiled path in that example [21]. The same output shows `GET /flights/:from-:to` falling back with the message that uWS cannot match this path on its own [14], which is the failure mode to expect. There is also an explain command for a single route, a Server-Timing middleware that surfaces the routing verdict in the browser network panel, and assertions you can put in a test so a route that drops off the fast path turns the build red [15]. On compatibility, every test in the suite runs against real Express first and then against Fulmine, with outputs required to match byte for byte, and Express 5's own suite is reported passing whole at 1130 passing, 0 failing on the pinned version [16]. helmet, cors, passport, morgan, multer, express-session, compression and express-rate-limit are not ported, they just run [17]. A second suite serves the same application twice across NestJS, Next.js as a custom server, Astro, SvelteKit, React Router v7, Apollo Server, tRPC and Angular SSR [18], with a NestJS adapter shipped in the package [19].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
Fulmine.js is a drop-in replacement for Express 5 that runs on uWebSockets.js instead of node:http.
The swap is one line: const express = require("fulmine.js") instead of require("express"); existing middleware keeps working.
Express's router walks a list: every request goes down the layers in order until one matches, so the more routes registered, the more work every request does.
On a small application nobody notices the router cost; on an application with a thousand routes, which is what a generated API layer or a multi-tenant backend looks like, it is the main cost of the request, and it is paid on every request before the application's own code runs.
Fulmine.js registers routes on uWebSockets.js's own router, which matches the path in C++ and hands over a chain worked out at startup, so nothing is scanned per request.
The published figures are spreads over the last nine CI runs, which landed on three different runner shapes, all on Node 26; the author says a single figure from a single run would not be honest.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Detailed but wholly self-reported
The cluster contains one source, written by the project's author, and it is unusually specific: named benchmark methodology (nine CI runs, three runner shapes, Node 26), an enumerated compiled-response precondition list, a reproduced profile output including a route that fails native matching, a stated Express 5 suite result of 1130 passing / 0 failing, and explicit wash cases at 1.0x-1.2x. None of it is independently reproduced or audited in the supplied material: the benchmark table itself is not included, HttpArena is cited but no arena figures are quoted, and the article text is truncated mid-caveat. Specificity and candour raise the score above bare vendor assertion; single-source provenance caps it well below verified.
No usage evidence supplied
The cluster shows a release announcement and the project's own test and benchmark runs, but no downloads, stars, dependent projects, production deployments or named users. Framework and middleware compatibility claims describe what the project tests against, not who has adopted it, so adoption cannot be measured without inferring facts the source does not provide.
Headline range outruns the evidence, though the author self-limits it
The framing headline is 2x-to-20x faster routing and 'no path through the framework', supported only by the project's own CI and by an unquoted external arena, with no adoption data at all — that is overstatement relative to available evidence. The gap is moderate rather than severe because the author does substantial deflation himself: spreads instead of a single number, an explicit statement that the gap is smallest on hello world, labelled wash rows at 1.0x-1.2x for SSE and WebSockets, narrow preconditions for the JavaScript-free path, a profile sample that shows a route falling off it, and the warning that Node 24 made Express roughly 3x faster on routing so earlier comparisons overstate the difference.
Author-published promotion of own project with self-run benchmarks
The single source is written in the first person by the creator of Fulmine.js on a developer publishing platform, promoting adoption of his package against an incumbent, with all performance and compatibility numbers produced by the project's own CI. That is a maximal alignment between the publisher and the subject. The score is not higher because the author explicitly flags the conflict ('numbers produced by a project about itself deserve suspicion'), publishes ranges and wash cases, and points readers to externally run comparisons.
Low: single interested source, truncated text, no adoption signal
Descriptive claims about what the package does are safe to restate because the source documents them directly, but every quantitative or comparative claim depends on one interested publisher with no corroboration, the supplied body cuts off mid-sentence in the final caveat, the referenced benchmark table is absent, and adoption is entirely unmeasured. Enough is verifiable about the design and tooling to assess the story at all; not nearly enough to trust the performance framing.
build
Five frameworks, one store, and a benchmark that measures when the button works1 distinct publisher
build
Rate limit your MCP servers, because a retrying agent turns one error into a billing incident1 distinct publisher
build
Your meter now runs on someone else's machine: signed receipts, fsync, and failing open1 distinct publisher
build
The optional EntityManager is the bug: moving the transaction boundary into AsyncLocalStorage1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 17, 2026