Hono v4.0
github.com
github.com
Ok, but what is it doing? How can it help me? The snippets subpage is empty. The examples have code directories with almost empty readmes.
> Hono … is a small, simple, and ultrafast web framework for the Edges. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, AWS Lambda, Lambda@Edge, and Node.js.
Hono is a JavaScript framework designed to run on (but not just) Edge runtimes. It’s nice due to it being very “lightweight”. It was mainly for server side functionality but this release adds more front end functionality, which I find quite welcome.
Personally I have found this works well if you’re targeting those platforms. For example, I use it on Cloudflare Pages with Page Functions and it works a dream.
I haven’t found it to be a write once target anywhere platform (for example, serving static files differs between platforms), but it makes it significantly less effort to migrate to a new platform if necessary, which is always nice.
"Hono
Fast, Lightweight, Web-standards
Runs on any JavaScript runtime."
lightweight = small code size
web standards = not node apis (fetch, not http.createClient, etc.)
runs on any JS runtime = runs in deno/node/bun/workers/etc
---
But yes the project is meant to be read by someone already in the field.
The people who actually know how to use it.
Yes it seems like a fancy combo of words if you don't know what they mean, but that's true for anything.
This is untrue: it's possible to make things much more accessible than they are here.
You write for an audience. This project could have written a description that works for "most programmers with any background at all in web development." Instead they chose a much narrower audience. People are complaining about that choice.
But it would be more fun to talk about the tech.
1. The OP is not the author of this project.
2. The project author did not know it was going to be directed at a more general audience.
3. They may have prepared the README for that if they knew.
4. Enjoy the tech and stop being so damn nitpicky HN
So to end this, I explained the tech and reason why:
Also "web standard API" doesn't really mean anything? Might just be because the authors are not native English speakers tho.
I'd rewrite the main description to "Hono: Fast, Lightweight, web framework to build APIs" or something. See FastAPI landing page [1] for a reference: "FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.8+ based on standard Python type hints." I know immediately what this is.
All of the code examples look like a slightly different syntax for express.js.
So it's a server side javascript framework for handling HTTP requests?
Since it targets multiple runtimes, I suppose it's "express.js but without the node.js dependency?".
I feel like that's closer, but I'm still missing the "why should I care?" part.
you can't run traditional http servers in edge sandbox worker environments.
frameworks like these target deno deploy, cloudflare workers, aws lambdas, etc.
they are small to fit in worker 1mb~ limits and use browser apis instead of node apis to fit the env.
bonus: sharing the same apis on the server and client also result in being able to share code client/server side.
You'd only care if you were in the "serverless" field, and then you'd likely already know about Hono since it's linked in many documentations like Supabase, Cloudflare, Deno, etc.
But you may not know about Hono because there are many options and some ways to be in serverless without seeing it yet and it's the newest framework I know of. (also my favorite so far other than raw deno)
--
This particular release was linked since it's one update that turns it into a real framework like Next or Astro.
They added 3 major features:
- Static Site Generation
- Client Components
- File-based Routing
Static site generation (SSG) would mean certain routes compile at build time and the worker won't compute them on the edge.
Client components means they now support client side rendering (CSR), before Hono was only used for server side rendering (SSR).
File-based routing is instead of coding your paths, the folder structure is used for routing, similar to Next which mimics how traditional http web serving works.
--
This is important for users of Hono as it unlocks features that exist in larger frameworks while still staying extremely minimal and flexible.
Hono + Postgres.js is getting pretty close to my ideal web stack.
IMO, SSR websites is the best way to get projects out quickly: predictable "builds", minimal surface area, boring tech, etc.
It helps that Hono has a very clean API :)
• https://taylor.town/pg-email-token
Here's a condensed version of how I do login/signup:
app.post("/signup", async c => {
const body = await c.req.parseBody();
const usr = {
email: body.email.toString(),
password: sql`crypt(${body.password.toString()}, gen_salt('bf', 8))`,
} as Record<string, unknown>;
const [{ usr_id, email, token }] = await sql`
with usr_ as (insert into usr ${sql(usr)} returning *)
select usr_id, email, email_token(now(), email) as token from usr_
`;
await sendVerificationEmail(email, token);
await setSignedCookie(c, "usr_id", usr_id, cookieSecret);
return c.redirect("/u");
});
app.post("/login", async c => {
const { email, password } = await c.req.parseBody();
const [usr] = await sql`
select *, password = crypt(${password.toString()}, password) AS is_password_correct
from usr where email = ${email.toString()}
`;
if (!usr || !usr.is_password_correct) return c.html(<p>Your password was incorrect.</p>);
if (!usr.email_verified_at) await sendVerificationEmail(usr.email, usr.token);
await setSignedCookie(c, "usr_id", usr.usr_id, cookieSecret);
return c.redirect("/u");
});My favorite truth in that site: "Anyway, instead of learning biochem and spanish I went and built this stupid website." I don't know what you are talking about at all.
This is typescript, which is interesting because we have more confidence the JS "works."
But, it is also embedding SQL directly into your typescript.
Isn't that a contradiction in code? I'm NOT suggesting you refactor to use an ORM or something!
When I was an Android developer, I thought it was really fascinating to see how Room worked. Each SQL statement you created was actually compiled and validated at compile time not runtime, and it meant the SQL was sanity checked and sanitized.
Nothing like that is happening here, right? You cannot validate this SQL at compile/build time? If not, aren't you YOLO riding the motorcycle but telling mom you are wearing your helmet?
Correct! It's a total pain haha.
I loathe SQL, but it's the best tool for most modern web apps.
All of flashcasts.com is 1800 lines. I'd guess 30% is HTML and 30% is SQL.
The SQL does the vast majority of the heavy lifting if you think about moving bits over distances.
So SQL is really important, but why don't I have any safeguards? Well, in my experience, the available safeguards are medicine more painful than the poison.
For example, any of the queries in my app I can copy-and-paste into psql and start an interactive debugging session. Can't do that with ORMs.
In my app, I dynamically aggregate and build all the podcast XML for every feed in a single Postgres query. It's super performant and surprisingly little SQL. Can't imagine doing that through an ORM.
SQL queries will throw an error if they're not well formatted, so you just have to write a test suite that somehow hits every query exactly once. You can do this by separating out your SQL, or integration tests, or a handful of other methods, none of which are pleasant.
Anyway, I'm tired of SQL, sol I'm working on an embedded query language in scrapscript. Stay tuned for details:
sql`select ${"hello"}, ${sql`world`}`
becomes select $1, world
[1] https://github.com/porsager/postgresIt's extremely minimalist, I just create a context object and implement in it any functionality I need such as headers, error handling, anything.
I even use it for "CLIs" that I then call with curlie.
I don't want those SSR oddities and react like "hooks" sneak into our backend codebase. They have been a constant source of confusion, bugs and performance issues in our frontend app.
Let me save you from typing the obligatory HN response: YoU DoNt HaVe tO UsE ThOsE
The performance (and especially pricing) is pretty wild and combined with various bindings (R2, KV, D1, AI, etc) general Cloudflare stuff, free egress, etc it can provide significant advantages.
That said looking at this I’m confused, to put it mildly, and I may start looking elsewhere. Back to itty-router?
Am I wrong or have others experienced this as well? Just having 1 package (to deploy vs 1 per endpoint) would be super nice in a number of ways and you could take advantage of things like provisioned concurrency (something much more difficult to plan for when you have a lambda per endpoint).
Maybe I’ll just branch my main project and see what happens as I move my code into a monolith with Hono but I’d love some feedback if others have experienced this and/or how they worked around it.
I guess you could still have multiple Hono-based packages that handle segments of your backend (verses all in one), is this how people are managing it?
i've done a few express apps on lambda, just because it was a free way to host fun projects and i didnt want to use a custom framework/tech, and they never got above 25MB zipped. big, but not really close to the limit (i believe 50MB)
Prisma doesn’t help matters but right now I take that hit on every function package anyway.
I might just need to try it one day (move my existing app to Hono to see if it would work).
"I guess you could still have multiple Hono-based packages that handle segments of your backend" -> I am thinking the same - if you hit bundle size problems, you can just split your app.
I'd also love to see some benchmarks how bigger bundle size impacts the performance - i.e. 1 MB adds additional 1ms on average, or so... My platform of interest is mostly Cloudflare Workers.
But if you have a sufficiently large enough API surface, doing one lambda per endpoint comes with a lot of pain as well. Packaging and deploying all of those artifacts can be very time consuming, especially if you have a naive approach that does a full rebuild/redeploy every time the pipeline runs.
I think there's a happy medium where you group lambdas by resource type or domain, but even still it can be tricky to enforce "least privileged access" for those when the content of the lambdas is constantly being added to. Eventually there is creep in the IAM permissions available to those lambdas.
I came up with a system that did incremental build/deploys for all of our lambdas based on the code changes since the last builds/deploys, but even so that came with some pain and definitely some hacks that I wouldn't do again (and relied on technologies it was difficult to get other people to engage with, like Bazel.) I also think Lambda (in particular of the FaaS options) is...not great for APIs, especially if you use a language with a long cold start time.
Yeah, thankfully SST [0] does the heavy lifting for me. I've tried most of the solutions out there and SST was where I was the happiest. Right now I do 1 functions per endpoint. I structure my code like url paths mostly, 1 stack per final folder, so that the "users" folder maps to "/users/*" and inside I have get/getAll/create/update/delete files that map to GET X/id, GET X, POST X, POST X/id, DELETE/id. It works out well, it's easy to reason about, and deploys (a sizable a backend) in about 10min on GitHub Actions (which I'm going to swap out probably for something faster).
I agree with the secrets/permissions aspect and I like that it's stupid-simple for me to attach secrets/permissions at a low level if I want.
I use NodeJS and startup isn't horrible and once it's up the requests as very quick. For my needs, an the nature of the software I'm writing, lambda makes a ton of sense (mostly never used, but when it's used it's used heavily and needs to scale up high).
[0] https://sst.dev
We used Go and the Serverless framework (ugh), and if I had to do it all over I would probably just use AWS SDK since it would make doing the "diff" to redeploy dead simple, since everything is just a binary to build.
Your use case definitely makes sense for Lambda APIs though! I think my complaint is more directed at APIs that back frontends. We had a JVM lambda API there for a while that was horrificly slow startup unless you set provisioned concurrency, which gets expensive fast.
I also looked at SEED and I would like to give them money but some of their methodology with SEED didn't fit with mine and since my deploys aren't horrible I left my system as-is. Also I understand they need to make money but I wish more tools geared towards serverless "scaled to zero". I'm happy to pay but my company has such bursty traffic that paying for a plan (on SEED or something like monitoring) that can handle our "peak" means burning money 70%-90% of the time while our app is scaled to zero but we still have to pay for tools around it.
Some monitoring tools, like New Relic, are based on usage but both NR and DataDog have absolute shit serverless monitoring solutions and their docs are a dumpster fire (at least around serverless). It's also unfortunate that most serverless monitoring means adding ~$10 per account per month (in increased AWS costs) just for their data pipelines to scan CloudWatch logs. This again sucks since we have an AWS account per client but each client is only active for ~1mo every year so it can get expensive fast.
Astro already solves many of the problems HonoX will run into, if a build step with Vite is acceptable for you. What I personally really want is an easy way to deploy exactly what I have locally and keep my dependencies small enough that shipping it unbundled isn't a problem for your project.
API-wise its very similar to most other file-based routers, including HonoX. Each file exports `GET`, `POST`, etc functions to handle requests.
I've been looking for a backend nodejs HTTP framework that is a) Typescript-first b) actually good that has file-system-based routing and so far haven't found anything. Adding HTTP methods on top of what nuxtjs' filesystem based routing does has me a little skeptical of what's possible, but I'll investigate Hono on this basis alone.
Also the "Edge-first" thing tells me this backend framework is probably better tree-shakable than what most other ancient/modern nodejs http servers have been doing. Cold starts will be better no matter where you deploy.
In webdev, I’ve been a huge fan of vite since it came out. Not having to wrangle configurations and bundlers and everything was very welcome. I wrapped it all up into a useful internal tool to play nice with our packages and splice together express+vite frontend. Then koa+vite. After playing with bun, I’m very keen on stack setups with convention over configuration (with config options) to just do the typescript thing, do esm, do it well.
I’m going to give this a go this weekend and see if this can replace our setup. Bun+Vite(React-TS)+Koa.
Hono - [炎] means flame in Japanese - is a small, simple, and ultrafast web framework for the Edges. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, and Node.js.
I agree, with this new major version the API surface of Hono became way too big, including so many features that don't seem to belong in the library. It's no longer small or simple. I will be searching for another library that stays true to its original simplicity.
I highly recommend it, and wrote more about it here: https://onlineornot.com/built-my-http-docs-from-scratch#conv...
[edit] I notice Azure support is under development. But the time frame could be ok if it has good tests & the project is well supported.
I highly recommend anyone looking into this to instead stick with larger, better community supported projects like Astro.