TanStack Hono - A SSR Monolith with Tanstack Router and Hono

Preface:
I’ve been using TanStack Router and Hono for a while and appreciate how well their philosophies align: TanStack Router gives you a strongly typed, data‑aware routing core; Hono provides a tiny, fast, standards‑leaning HTTP layer that runs comfortably on Node or edge platforms.
This project explores combining them into a single SSR + CSR monolith for TypeScript: one process (in dev) that can server‑render React routes, hydrate on the client, and expose lightweight API/RPC endpoints without jumping to a heavier meta‑framework.
Rather than serving the router purely as an SPA (what I had previously done) or using Hono/JSX, I adapted the official TanStack Router SSR example—swapping Express for Hono and layering in a typed API example to illustrate a simple RPC style.
Repo: github.com/bskimball/tanstack-hono
Development uses the Hono dev server with Vite powering both the client bundle and the server entry, so hot reloading applies across routes, server handlers, and shared types.
Why Hono?
Hono is a minimalist web framework that emphasizes performance and simplicity. It has a small footprint, making it ideal for serverless and edge environments. Its middleware system is straightforward, allowing for easy composition of request handlers. With its middleware, it’s easy to have RPC, Zod validations, and an OpenAPI compatible REST API.
Why Tanstack Router?
TanStack Router is a powerful routing library that provides strong typing and data awareness. It allows for nested routes, route loaders, and seamless integration with React. Its focus on type safety helps catch errors at compile time, making it a great fit for TypeScript projects. Additionally, TanStack Router’s flexibility allows it to be used in various environments, making it a versatile choice for building web applications.
Why a “Monolith”?
Monolith here simply means: one repository + one runtime process (in dev) that handles:
- HTTP routing (API + SSR HTML responses)
- React server rendering + hydration delivery
- Static asset compilation (Vite)
- Type‑safe internal RPC style endpoints
The goal is to keep operational complexity low while still enabling progressive enhancement and dynamic UI.
Architecture Overview
High level flow:
- Request enters Hono.
- Path is checked against API / RPC routes (e.g.
/api/todos
). If matched: handler runs, JSON returned. - Otherwise SSR handler:
- Creates a TanStack Router instance with the route tree
- Resolves the matching route elements (no framework‑specific loader layer)
- Renders React to string / stream
- Injects serialized router state + asset tags
- Client hydrates the router instance; subsequent navigation is client‑side.
This pattern mirrors the official TanStack Router SSR example, replacing Express with Hono and integrating its middleware ergonomics + performance.
File / Responsibility Layout (Conceptual)
src/ # createRouter(), renderToString(), HTML template
components/ # Shared React components
Header.tsx # Example shared header
routes/
__root.tsx # Root route with layout + <Outlet />
index.tsx # / home route
about.tsx # /about
todos/
index.tsx # /todos list
$id.tsx # /todos/:id detail
api/
todos.ts # Example Hono route or RPC style handler
shared/
types.ts # Shared Zod / TS types for API + UI
entry-client.tsx # Hydration entry
entry-server.tsx # Server render entry (invoked by ssr.ts)