Since “Express.js is an old framework that has not evolved for a long time. It’s not a good choice for new projects since it can easily lead to security issues and memory leaks.” — H3. Which is also the case for Koa.
The focus here will be on those frameworks which support running service workers on the server-side and the modern Fetch API standard, so they can be run in Serverless and Edge environments (Cloudflare Workers etc.). So Fastify didn’t make the cut for this article, even though it has a 2 year old experiment called fastify-edge. (But they wrote an excellent piece about the evolution from Node to Worker Environments that I recommend reading afterwards.)
Worker Runtimes fulfill the original promise of NodeJS: To use one language and share code between client and server. In practice, this never came to be. Instead the APIs of node and browsers have diverged. Worker Runtimes are bringing them back together. https://workers.js.org/#backend-for-frontend
Hono, H3, HatTip and Elysia are such next generation HTTP server frameworks (aka. web server middlewares). They run everywhere, on any JS runtime, even Serverless and Edge runtimes. Meaning not just on Node.js servers. They are also all TypeScript friendly.
Here’s a quick overview of each, and then a comparison of some essential distinctions. (I had to dig up this information from a lot of various sources, so hopefully it’s helpful to you all that it’s now available here when you Google it.)
All of them have support for the Web Fetch API (Request/Response objects). But I’ll show their most Express-like API’s here, for familiarity.
Hono‘s API is similar to Express:
import { Hono } from 'hono';
const app = new Hono();
app.get('/hello', (c) => {
return c.json({ message: 'Hello!' });
});
export default app;
Repo started: Dec 12, 2021 – https://github.com/honojs/hono
Main contributors: 2.5
Github stars now: 12.4 k
NPM weekly downloads now: 143 796
Current state: Hono is on version 4+.
Tagline: “Fast, Lightweight, Web-standards. Runs on any JavaScript runtime.”
Made for Cloudflare Workers first, but has a Node adapter. But Hono on Node seems terribly slow. But this is not reflected in the other benchmark: Web Frameworks Benchmark.
Hono is very web standards focused.
Hono has an RPC feature.
Hono aims to have batteries included: built-in, custom, and third-party middlewares, and helpers.
H3 allows manually registering router instances:
import { createApp, createRouter, defineEventHandler, toNodeListener } from "h3";
import { createServer } from "node:http";
export const app = createApp();
const router = createRouter();
app.use(router);
router.get('/', defineEventHandler((event) => {
return { message: 'Hello!' };
}),
);
createServer(toNodeListener(app)).listen(8000);
Repo started: Nov 15, 2020 – https://github.com/unjs/h3
Main contributors: 1.5
Github stars now: 2.9 k
NPM weekly downloads now: 976 744
Current state: H3 is on version 1.11.1.
Tagline: “The Web Framework for Modern JavaScript Era: H(TTP) server framework built for high performance and portability running in any JavaScript runtime.”
“H3 is a composable [and tree-shakeable] framework. Instead of providing a big core, you start with a lightweight app instance and for every functionality, there is either a built-in utility or you can make yours. Composable utilities have huge advantages comparing to traditional plugin/middleware approaches: …” https://h3.unjs.io/utils
H3 was extracted from Nitro/Nuxt around Jul 2, 2023 or later. Which may explain the relatively lower amount of github stars.
Made for Node first, but has adapters for Serverless or Edge JS runtimes (Cloudflare Workers etc.). H3 can also run on Bun with an adapter. This is not reflected in the bun-http-framework-benchmark yet, so follow this issue to see when it’s added.
H3 integrates with the UnJS ecosystem of JS tools.
NuxtJS (Vue meta-framework) is built upon Nitro (http-server extensions) which is built upon H3. Nitro adds file-based routing, asset handling, storage abstraction, etc. onto H3. (Nitro can selectively use Vite in one of its routing handlers, since Vite is only needed for the client server, not the static server, according to Nikhil, author of Vinxi.)
HatTip also has an Express style imperative routing API:
import { createRouter } from "@hattip/router";
import { json } from "@hattip/response";
const router = createRouter();
router.get("/", () => {
return json({ message: "Hello!" });
}
export default router.buildHandler();
Repo started: Feb 20, 2022 – https://github.com/hattipjs/hattip
Main contributors: 1.5
Github stars now: 1.1 k
Weekly downloads now: 1 299
Tagline: “Like Express, but for the future”.
Current state: HatTip is on version 0.0.44. (Generally, people consider version 1.0 to represent production-ready.)
HatTip should work well with the Vite-based NextJS alternative Vike (aka. vite-plugin-ssr) since HatTip is made by the same guys.
HatTip integrates with graphql-yoga.
Elysia uses chaining / a fluent interface for type inference, and gets a distinct style:
new Elysia()
.get('/json', () => ({
message: 'Hello!'
}))
.listen(8080);
Repo started: Jul 3, 2022 – https://github.com/elysiajs/elysia
Main contributors: 1
Github stars now: 7.1 k
Tagline: “Ergonomic Framework for Humans”.
Current state: Elysia is on version 0.7. (Generally, people consider version 1.0 to represent production-ready.)
All of the frameworks are very web standards focused: Fetch API (the current standard) & WinterCG (the future standard).
Github stars
Hono and Elysia has had a meteoric rise in GitHub stars:
For the current up-to-date statistics, see: GitHub star history graph for Hono vs. H3 vs. HatTip vs. Elysia.
NPM downloads
H3 is by far the most downloaded, likely because being included with Nitro and NuxtJS (the NextJS of the Vue world):
If we exclude H3 and zoom in:
But how is their rate of growth changing? I.e. How fast do they grow?
Hono is currently growing quickest in NPM downloads month-over-month, with 26.6 % growth. Elysia has 17.9 %, quickly followed by HatTip with 17% and surprisingly the incumbent H3 at last with 15.3 % growth in NPM downloads.
For the current up-to-date statistics, see: NPM and GitHub comparison statistics on Moiva.io for Hono vs. H3 vs. HatTip vs. Elysia.
Performance and benchmarks
Take all benchmarks with a pinch of salt. More than likely, all of these frameworks will be fast enough for most use cases, and it’ll be your app logic that’s the bottleneck. With that said, here are some benchmarks (contribute more, and I’ll add them).
Denosaurs’ helloworld benchmark. Results in requests per second (RPS):
Framework | RPS |
---|---|
Elysia: | 77 140 |
Hono: | 49 743 |
H3: | N/A |
HatTip | N/A |
Web Frameworks Benchmark, from the-benchmarker’s github repo. Results in request per second (RPS), and with concurrency 64:
Framework | RPS |
---|---|
Hono (Bun) | 131 177 |
H3 (Node?): | 75 422 |
Hono (Node?): | 68 263 |
Elysia (Node?): | 64 793 |
HatTip is not yet in this benchmark.
SaltyAom/bun-http-framework-benchmark (from ElysiaJS author).
Results, in requests per second (RPS), on the repo’s official benchmark (ran on an Intel-Core-i7-13700K CPU):
Framework | RPS |
---|---|
Elysia (Bun): | 255 574 |
Hono (Bun): | 203 937 |
H3 (Node): | 96 515 |
Hono (Node): | 29 036 |
Some other guy, running the same test on Linux, on a generally slower machine:
Framework | RPS |
---|---|
Elysia (Bun): | 86 841 |
Hono (Bun): | 73 614 |
He didn’t test the other frameworks.
And another guy on Linux, on a slightly slower CPU than the official benchmark:
Framework | RPS |
---|---|
Elysia (Bun): | 199 328 |
Hono (Bun): | 196 504 |
H3 (Node): | 95 482 |
Hono (Node): | 20 781 |
Hono could allegedly be made about 20 % faster on the Bun benchmark. Hono on Node seems terribly slow. But this is not reflected in the other benchmark: Web Frameworks Benchmark.
The above tests and info indicate that Elysia and Hono are about as fast when run on Bun.
HatTip is allegedly about as fast as Hono, when both are run on Bun.
Hono uses a faster RegExpRouter instead of a Radix Tree based router such as Radix3 which H3 uses. But follow this issue to see if H3 implements the same RegExpRouter, or if it is upstreamed to radix3. But in general, it’s likely that the router performance won’t matter much, since it will be dwarfed by the time it takes to execute user logic.
What can be counter-intuitive is that some web frameworks that perform worse on a raw text (i.e. helloworld) response, can perform better than the others when querying a Postgres DB, likely due to specific optimisation. So the rankings can shift, depending on use case.
“If you are looking for the best performing nodejs framework, you should consider that the performance drops on all frameworks the moment you query a database. In that scenario, the difference in performance between the fastest and the slowest is reduced and other factors come into play.” — Yet another nodejs benchmark
Distinctions / focus
HatTip is more standards focused than Hono. At least when it comes to universal middlewares.
HatTip also focuses on:
Whereas «Hono is just a web framework. That will not change in the future. No possibility of bundling CLI, at least not at this stage.«: according to it’s author.
HatTip is better suited for (deeper integrated with) Vite than Hono (which requires plugins).
Other
Cutting-edge tooling like Vinxi (used by Solid Start and Tanstack Start) bets on H3 over Hono:
From Vinxi’s perspective, it’s way better to bet on H3 which is backed by the Nitro and UnJS teams and is used by Analog and Nuxt. So lot of people working on keep it stable, fast, bug free and working everywhere. (and its still quite a difficult task).
— said Nikhil Saraf (Vinxi’s author).
But it might also be due to other reasons, such as H3 allowing manually registering router instances (which is Vinxi‘s main feature).
Did I forget something important?
Please comment, and I’ll try to update the article so the overview is better!