I created a pet project (REST API) with Hono and I'm seriously considering using it for future projects instead of what has been my go-to stack for years (Express, lately with Zodios).
Hono's middlewares, especially zod-openapi[1] and @scalar/hono-api-reference[2], make it really easy to define your REST endpoints once and get full typesafe routes with request/response validation, an automatic OpenAPI spec, a beautiful OpenAPI browser and you can even reuse the typings in your frontend with Hono's RPC[3] middleware, essentially giving you end-to-end type-safety without any code-generation.
Its maintainer yusukebe is a really nice guy who is always being helpful and very active. I want Hono to become the modern successor of Express. :)
I'm very curious, I'm learning from both HonoJS and ElysiaJS about how to build a great next-generation library, and the thing that strikes me from Hono is that it seems it has integration for a lot of things, BUT you have to write a lot of manual code for those instead of "extending the base Hono" so to speak. For the `zod-openapi` example you gave, I'm looking at the docs and it seems there's no import in common from hono to hono/zod-openapi project:
import { z } from '@hono/zod-openapi'
import { createRoute } from '@hono/zod-openapi'
import { OpenAPIHono } from '@hono/zod-openapi'
I would have expected/hoped things to be more integrated, e.g. you still do `import { Hono } from 'hono'` and then somehow you connect to this OpenAPI middleware. Any thoughts on this? Do you feel like moving from "base Hono" to use hono/zod-openapi you have to change how you do things? Another place I've seen this pattern is with the different edges, you have different import/exports, which I understand to certain degree but I still think a bit more could be done at the base library.
That's actually something I find a bit awkward, too. Especially, there was no way to re-use the global Hono error handler for all OpenAPI routes. I created an issue[1] with my suggested workaround and was told that that's the way to go. Maybe things are that way because `zod-openapi` was introduced later on. But I believe in the end it doesn't really matter that much as the code is clean and readable. :)
We are using a similar stack. I assume your client is located in the same repo as your server? That's a no-go for us, so we're planning on using the OpenAPI spec to generate a type-safe frontend client. I kind of wish it was as easy as using the RPC middleware, though.
In cases where the client needs to stay separate, we have had a good experience with Orval[1] to generate a fully-typed @tanstack/query client from our OpenAPI spec.
Recently, I've been looking for a suitable stack for another pet project. Personally my go-to stack is Remix.
But I want to use a server other than the default provided by Remix, i.e minimal Express. So, I found Hono. It looks interesting because it can run on many runtimes, and this time I want to try using Bun.
After researching Hono, it turns out it can render JSX directly from the server, which piqued my interest. Then I tried to make the JSX interactive, and finally, I used htmx. Lol.
And just yesterday, after spending hours I found a way to use PDFKit with Hono (Bun runtime), so I created a gist for reference:
> After researching Hono, it turns out it can render JSX directly from the server, which piqued my interest. Then I tried to make the JSX interactive, and finally, I used htmx. Lol.
HTMX is fine if you want to avoid writing client side JS, but Hono did add support for client components in version 4 [1]. There's even an esbuild middleware that can transpile TS/TSX files on the fly (the Deno framework Fresh uses a similar technique) [2].
Hono client components are interesting. But I couldn't find any docs on how it's implemented and how that implementation compares to React/Preact/Solid etc.
I've been using Hono + Bun + SQLite for all my personal projects, and I really like it. Essentially, I've replaced Express and Node with it. What I appreciate the most is how quickly I can set up a project with Bun, have native SQLite connector, and how minimal the Hono base app is. Additionally, I can use JSX without any setup hassle.
The README.md says RegExpRouter uses no loops and just regular expressions, presumably it maps a route to a hashmap matched entry?
Related but slightly different:
I am curious because NFAs, deterministic automata are interesting to me. I remember one person on HN talked to me about using regular expressions to match event sequences. (That is: don't match against strings but match against tokens)
I am not a Rust developer, but the pattern of using Rust sum types and pattern matching or OCaml dispatch based on types are similar to me intuitively.
What are your thoughts on this style of programming?
I feel so much of modern business programming is dispatch logic!
If you think of Redux and state machines and event sequences in GUIs for behaviour, I feel there is a lot of untapped potential ideaspace here.
The regexprouter compiles all of the routes into a single matcher, so you're not doing a linear search of all of your routes (lots of routers are essentially doing an if else on all of the routes).
They also have a similar trie router, but my understanding is that it's not as fast.
The benchmark that's provided says nothing, actually. Being able to serve half a million requests per second isn't a useful measurement for two reasons:
1. In a serverless environment, _the whole point_ is that the requests are essentially all concurrent. If you get 1000 requests at T+0, you get 1000 concurrent invocations of your function. The overhead of the worker doesn't stack unless you hit a concurrency limit, which most folks won't.
2. The overhead of the framework is a rounding error. The slowest framework benchmarked clocks in at over 200K QPS. That's ones of microseconds of overhead from the framework per request. HonoJS is still ones of microseconds per request. If your application code takes one millisecond to return meaningful output, that's _hundreds of times slower_ than the overhead, and the framework's performance is already moot.
Choose a framework that is nice to use and gives you all of the features you want. Shaving off a handful of kilobytes of source code _on the server_ is premature optimization. Shaving off a few microseconds from the request time is premature optimization. Even "heavy" frameworks like Koa and Express will give you good-enough performance that you probably wouldn't ever even notice. What matters is the tool you choose that helps you build useful stuff faster.
At first glance, Hono seems like the most standards-compatible framework.
> It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, AWS Lambda, Lambda@Edge, and Node.js.
Not sure it counts as “any JS runtime” if it does not work in browser (e.g., worker context), but judging by the rest of the docs it might work there, too.
It also even works in Wasmer Edge (template here: https://wasmer.io/templates/hono-starter )... I'm incredibly impressed with how much effort they have been putting on the framework, I bet they will win big time!
Yes it works in the browser also. I've been using it for routing and templating etc client side (main thread, and service worker), as well as in a cloudflare worker.
Hono's middlewares, especially zod-openapi[1] and @scalar/hono-api-reference[2], make it really easy to define your REST endpoints once and get full typesafe routes with request/response validation, an automatic OpenAPI spec, a beautiful OpenAPI browser and you can even reuse the typings in your frontend with Hono's RPC[3] middleware, essentially giving you end-to-end type-safety without any code-generation.
Its maintainer yusukebe is a really nice guy who is always being helpful and very active. I want Hono to become the modern successor of Express. :)
[1] https://hono.dev/snippets/zod-openapi
[2] https://www.npmjs.com/package/@scalar/hono-api-reference
[3] https://hono.dev/guides/rpc
> beautiful OpenAPI browser
> end-to-end type-safety without any code-generation
That's a great sales pitch - I'd looked at Hono before but now I've opened all the links you mentioned and will try it out.
[1] https://github.com/honojs/middleware/issues/323#issuecomment...
[1] https://orval.dev/
But I want to use a server other than the default provided by Remix, i.e minimal Express. So, I found Hono. It looks interesting because it can run on many runtimes, and this time I want to try using Bun.
After researching Hono, it turns out it can render JSX directly from the server, which piqued my interest. Then I tried to make the JSX interactive, and finally, I used htmx. Lol.
And just yesterday, after spending hours I found a way to use PDFKit with Hono (Bun runtime), so I created a gist for reference:
https://gist.github.com/mansarip/eb11b66e7dc65cee988155275a1...
Anyway I'm still cautious about putting this Hono + htmx stack into production use.
HTMX is fine if you want to avoid writing client side JS, but Hono did add support for client components in version 4 [1]. There's even an esbuild middleware that can transpile TS/TSX files on the fly (the Deno framework Fresh uses a similar technique) [2].
[1] https://hono.dev/guides/jsx-dom
[2] https://github.com/honojs/middleware/tree/main/packages/esbu...
The README.md says RegExpRouter uses no loops and just regular expressions, presumably it maps a route to a hashmap matched entry?
Related but slightly different:
I am curious because NFAs, deterministic automata are interesting to me. I remember one person on HN talked to me about using regular expressions to match event sequences. (That is: don't match against strings but match against tokens)
I am not a Rust developer, but the pattern of using Rust sum types and pattern matching or OCaml dispatch based on types are similar to me intuitively.
What are your thoughts on this style of programming?
I feel so much of modern business programming is dispatch logic!
If you think of Redux and state machines and event sequences in GUIs for behaviour, I feel there is a lot of untapped potential ideaspace here.
They also have a similar trie router, but my understanding is that it's not as fast.
1. In a serverless environment, _the whole point_ is that the requests are essentially all concurrent. If you get 1000 requests at T+0, you get 1000 concurrent invocations of your function. The overhead of the worker doesn't stack unless you hit a concurrency limit, which most folks won't.
2. The overhead of the framework is a rounding error. The slowest framework benchmarked clocks in at over 200K QPS. That's ones of microseconds of overhead from the framework per request. HonoJS is still ones of microseconds per request. If your application code takes one millisecond to return meaningful output, that's _hundreds of times slower_ than the overhead, and the framework's performance is already moot.
Choose a framework that is nice to use and gives you all of the features you want. Shaving off a handful of kilobytes of source code _on the server_ is premature optimization. Shaving off a few microseconds from the request time is premature optimization. Even "heavy" frameworks like Koa and Express will give you good-enough performance that you probably wouldn't ever even notice. What matters is the tool you choose that helps you build useful stuff faster.
> It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, AWS Lambda, Lambda@Edge, and Node.js.
Not sure it counts as “any JS runtime” if it does not work in browser (e.g., worker context), but judging by the rest of the docs it might work there, too.
Does it work in the browser as well?