How I Use Hono and Tanstack Start
I’ve never liked using any of the fullstack web frameworks for apis. They lack clear middleware and routing, they never quite support openapi and the types are often more difficult to work with. I see lots of people use tRPC or oRPC to try to smooth out the rough edges, but most of my side projects rely on heavy caching and RPC is inheirtly shit at caching at the CDN lavel because it makes post requests. Nextjs is the worst offender here, api middleware is a complete nightmare to understand.
The two options for using hono as I see it are:
- Use vite to start a hono server that loads tanstack start. This was popular how most remix+hono projects tend to be structured.
- Use tanstack start to route api requests to a hono server. This is the pattern I’ve been using for a while now and it’s working well for me.
Hono up front
I see the appeal of using hono up front to do all routing, you can inject everything you want and have the last word on the request/response via middleware. https://github.com/bskimball/tanstack-hono shows this off really well. I think the main tradeoffs here are that you have a way more custom vite config and a bit more of a custom build process which might be difficult to maintain especially as tanstack continues to iterate on the vite plugin leading up to the stable release. You’ll notice it runs npm run build:client && npm run build:server && npm run build:types to build which creates different bundles via vite.
Hono in the back
I like to have hono sit in the back during development and then bring it to the front in production, which is a little funky but you only need to set up the production side once. The advantage here is that you don’t need to customize the vite config. Tanstack start can pass requests to hono via an api wildcard route.
// src/routes/api/$.ts wildcard api route
import { createFileRoute } from '@tanstack/react-router';
import { app } from '../../../server/app';
const serve = async ({ request }: { request: Request }) => {
return app.fetch(request);
};
// Route all api requests to the hono server
export const Route = createFileRoute('/api/$')({
server: {
handlers: {
GET: serve,
POST: serve,
PUT: serve,
DELETE: serve,
PATCH: serve,
OPTIONS: serve,
HEAD: serve,
},
},
});