Hono RPC Type Inference Issues with Nested Routes in Monorepo

Hi everyone! I'm fairly new to Hono and still learning, so I apologize if I'm missing something obvious or doing something wrong. I'm working on a monorepo project using Next.js (frontend) and Hono (backend) with Hono RPC for type-safe API communication. I'm experiencing issues where some API routes are not properly typed on the frontend, possibly due to deep nesting in the type definitions. Project Structure: - Monorepo: pnpm workspace - Backend: Hono (apps/api) with RPC support - Frontend: Next.js 15 (apps/web) - Repository: https://github.com/Shiyo1101/hackathon-nishiyama-canvas Current Setup: Backend (apps/api/src/index.ts):
import { Hono } from "hono";
import { signageRoutes, publicSignageRoutes } from "./modules/signage";

const apiRoutes = new Hono()
.route("/signages", signageRoutes)
.route("/public/signages", publicSignageRoutes);

const app = new Hono()
.route("/api", apiRoutes);

export type AppType = typeof apiRoutes;
import { Hono } from "hono";
import { signageRoutes, publicSignageRoutes } from "./modules/signage";

const apiRoutes = new Hono()
.route("/signages", signageRoutes)
.route("/public/signages", publicSignageRoutes);

const app = new Hono()
.route("/api", apiRoutes);

export type AppType = typeof apiRoutes;
Frontend (apps/web/src/lib/api-client.ts):
import type { AppType } from "@api/index";
import { hc } from "hono/client";

export const apiClient = hc<AppType>(API_URL, {
init: {
credentials: "include",
},
});
import type { AppType } from "@api/index";
import { hc } from "hono/client";

export const apiClient = hc<AppType>(API_URL, {
init: {
credentials: "include",
},
});
The Problem: When trying to use the RPC client on the frontend, some routes work fine but others don't seem to have proper type inference. For example, this might work: apiClient.api.signages.$post() but nested routes or certain endpoints lose type information. Questions: 1. Is there a recommended pattern for exporting types when using nested routes (route() chaining)? 2. If there's a better approach for type sharing, I'd love to hear about it. I tried Zod OpenAPI Hono but couldn't figure out how to integrate it with Better Auth, so I gave up on that approach. 3. If there are any existing threads discussing and solving similar issues, I'd appreciate if you could share them. Any insights or suggestions would be greatly appreciated! Thanks in advance! 🙏
GitHub
GitHub - Shiyo1101/hackathon-nishiyama-canvas
Contribute to Shiyo1101/hackathon-nishiyama-canvas development by creating an account on GitHub.
3 Replies
ambergristle
ambergristle2mo ago
https://hono.dev/docs/guides/best-practices https://hono.dev/docs/guides/rpc the key piece is that you should be generating declaration files for your backend, and importing the types from those into your frontend/client rather than directly
// should work
import type { AppType } from '@api/types'; // `/api/types.d.ts'

// type instantiation possibly infinite
import type { AppType } from '@api/index'; // `/api/index.ts`
// should work
import type { AppType } from '@api/types'; // `/api/types.d.ts'

// type instantiation possibly infinite
import type { AppType } from '@api/index'; // `/api/index.ts`
but there are also some other tricks that can help all routes you want to show up in the type must be chained openapi isn't a type-sharing solution. you can use it to generate a spec, and generate a client from the spec or w/e, but it's not going to give you any more type-safety than vanilla hono RPC i would recommend hono-openapi instead of hono/zod-openapi there are a bunch of threads about this on the server, and probably github issues as well. i'd recommend searching through them
◡̈うっちー
Thank you so much for the detailed guidance! I realized that I wasn't following the best practices properly and hadn't read the documentation thoroughly enough. After implementing according to the best practices you shared, the type inference is now working perfectly! Really appreciate your help! 🙏
ambergristle
ambergristle5w ago
no problem! happy coding

Did you find this page helpful?