Route Generation
How Nooh compiles file-based routes into typed Hono modules and native route handlers.
When you run nooh build, nooh dev, or use the Nooh bundler plugin, the Nooh compiler inspects your routes directory and generates fully typed route modules inside .nooh/.
The .nooh Directory
The compiler produces a mirror of your routes structure along with helper artifacts:
.nooh
router
users
What is generated?
app.ts: The main entry point creating the rootHonoinstance, registering all global middleware, mounting sub-routers, and exporting the final application.router/middleware.ts: Helper wrappers for defining typed middlewares matching your global environment.router/**/*.ts: Per-route helper modules exporting method functions (such asget,post,put,del,patch,options,head,all).
The @router/* Alias
Nooh uses a path alias configured in your tsconfig.json so you can cleanly import route helpers from anywhere without relative clutter:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"],
"@router/*": ["./.nooh/router/*"]
}
}
}
When authoring src/routes/users/[id].get.ts, you import from @router/users/[id]:
import { get } from "@router/users/[id]";
export default get((c) => {
const { id } = c.req.param();
return c.json({ id });
});
Anatomy of Generated Route Modules
Each generated file in .nooh/router/ provides method builder functions tailored specifically for that route.
Type Signature & Overloads
Generated method functions support multiple call styles:
// 1. Plain handler
export default get((c) => c.text("Hello"));
// 2. Options object with validation, dependencies, or route-level middleware
export default get({
schema: {
param: userParamSchema,
},
deps: [userService],
handler: (c) => {
const { id } = c.req.valid("param");
const user = c.deps.userService.findById(id);
return c.json(user);
},
});
Route Metadata
The generated route handler embeds internal metadata (Symbol.for("nooh.route")) used by the Nooh compiler during the introspection and diffing phases:
const NOOH_ROUTE_METADATA = Symbol.for("nooh.route");
This allows the compiler to inspect declared dependencies, validation schemas, and error boundaries during compilation without having to execute runtime code.
Incremental Compilation & Caching
The compiler performs dependency graph analysis and diffing to keep your development workflow instant:
- Only changed routes recompile: If you edit a single file in
routes/, only that route’s helper module is regenerated. - Strict type safety: If you change a route parameter from
[id]to[slug], TypeScript immediately reports errors wherec.req.param("id")is accessed. - Zero runtime overhead: The generated code compiles down to vanilla Hono handlers. No reflection, runtime filesystem scanning, or regex parsing takes place at request time.