Build Hono APIs.
Nooh compiles the rest.
File-based routing, type-safe composition,
dependency injection, middleware and typed errors —
compiled into native Hono.
app.get('/users/:id', ...)Your filesystem is your router.
Your route structure is derived from the filesystem and compiled into normal Hono routes. Nooh reads your files, analyzes your types and generates a Hono app at build time.
Type-safe dependency injection built-in.
Declare your dependencies in modular containers and inject them directly into route handlers. Context properties are automatically typed with static error detection for duplicates and invalid references.
import { container } from "nooh";
import { UsersRepository } from "...";
export const db = container({
users: () => new UsersRepository(),
});import { post } from "@router/users/[id]";
import { db } from "@deps/db";
export default post({
deps: [db.users],
handler: async ({ c, users }) => {
const user = await users.getById(c.req.param("id"));
return c.json(user);
},
});Auto-typed Context
Injected dependencies likeusersare automatically typed on the handler argument.
Production Safety
Detects duplicate dependencies, invalid references, and unhandled errors at compile time.
Zero Runtime Overhead
Dependencies are resolved during build time into standard Hono application code.
Declarative, fully-typed error helpers.
Declare any class extendingErrorin your route signature. Error factories are automatically bound to the handler context with full parameter inference and minimal runtime cost.
export class UserNotFound extends Error {
constructor(public userId: string) {
super(`User ${userId} not found`);
}
}
export class UnauthorizedAccess extends Error {
constructor() {
super("Unauthorized access");
}
}import { get } from "@router/users/[id]";
import { db } from "@deps/db";
import { UserNotFound, UnauthorizedAccess } from "@errors/user";
export default get({
deps: [db.users],
errors: {
notFound: UserNotFound,
unauthorized: UnauthorizedAccess,
},
handler: async ({ c, users, errors }) => {
const id = c.req.param("id");
const user = await users.getById(id);
// strongly typed error factory
if (!user) throw errors.notFound(id);
return c.json(user);
},
});Typed Error Factory
Declared errors map directly toerrors.<key>()helpers with inferred constructor parameters.
Standard Error Support
Use any class extendingErrorwith full custom constructor arguments support.
Minimal Runtime Cost
Compiles directly into optimized standard logic without additional runtime abstraction overhead.
First-class Standard Schema validation.
Define request validation in thevalidationobject using any Standard Schema library (Zod, Valibot, ArkType). Nooh compiles it with@hono/standard-validatorby default, or your choice of custom validator.
import { post } from "@router/users";
import { z } from "zod";
const createUserSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
});
export default post({
validation: {
json: createUserSchema,
},
handler: async ({ c }) => {
// validated payload is automatically typed
const data = c.req.valid("json");
return c.json({ user: data }, 201);
},
});import { config } from "@nooh-ts/nooh";
import { zValidator } from '@hono/zod-validator'
export default config({
// Optional: swap default @hono/standard-validator
// with any custom or Hono-supported validator
validator: {
engine: zValidator,
},
});Standard Schema Compliant
Works seamlessly with Zod, Valibot, ArkType, or any library implementing the Standard Schema specification.
All Hono Request Targets
Validatejson,query,param,header, orform.
Pluggable Engine
Easily swap the default validator engine for any other Hono validator or custom validation logic.
Scoped route & group middleware.
Create type-safe middleware with the@router/middlewarehelper. Apply them per route or cascade them across entire route subtrees with$.tsgroup files.
import logger from "@middleware/logger";
import { group } from "@nooh-ts/nooh";
// applies to all routes under /users/*
export default group({
middleware: [logger],
});import { middleware } from "@router/middleware";
export default middleware(async (c, next) => {
const start = Date.now();
await next();
const duration = Date.now() - start;
console.log(`${c.req.method} ${c.req.path} ${c.res.status} ${duration}ms`);
});File-System Grouping
$.tsfiles represent route groups, easily scoping middleware across entire subtrees.
Type-Safe Context
Standard Hono contextcandnext()functions with full type inference and environment bindings.
Cascading Execution
Group middleware executes before route-level middleware, providing predictable, hierarchical pipeline execution.
Write Nooh. Ship Hono.
Nooh uses your routes, dependencies, middleware and errors as compile-time composition. The generated application is ordinary Hono code with no Nooh runtime.
import { post } from "@router/users/[id]";
import { db } from "@deps/db";
import { UserNotFound } from "@errors";
import logger from "@middleware/logger";
export default post({
deps: [db.users],
errors: { notFound: UserNotFound },
middleware: [logger],
handler: async ({ users, error, c }) => {
const user = await users.getById(c.req.param("id"));
if (!user) {
throw error.notFound();
}
return c.json(user);
},
});// Conceptual generated output
import { Hono } from "hono";
import type { App } from "./types.js";
import { UsersRepository } from "../src/deps/db.js";
import UserNotFound from "../src/errors/UserNotFound.js";
import logger from "../src/middleware/logger.js";
const users = new UsersRepository();
const app = new Hono<App>();
app.post("/users/:id", logger, async (c) => {
const user = await users.getById(
c.req.param("id")
);
if (!user) {
throw new UserNotFound();
}
return c.json(user);
});
export default app;Runs anywhere Hono runs.
Nooh compiles into native Hono applications. You get 100% compatibility with the entire Hono ecosystem, official middleware, and any JavaScript runtime out of the box.
Universal Runtimes
Deploy your API on any JavaScript runtime or edge infrastructure without modifying a single line of application logic.
Full Hono Ecosystem
Use any existing Hono middleware, official packages, or third-party community extensions seamlessly.
Zero Lock-in
Hono is the entrypoint. Your project compiles to readable standard TypeScript that you own completely.
Modern TypeScript ergonomics.
Production ready Hono output.
Nooh gives you the structure and developer experience of a modern framework, with the performance and simplicity of Hono — and it disappears after compilation.
Type-safe
Full TypeScript support, from routes to context and errors.
Modular
Composed dependencies, middleware and logic.
File-based
Your filesystem defines your API surface.
Simple
No complex config. No magic.
Composable
Dependency injection, middleware and logic.
Fast
Zero runtime overhead. Just Hono.
A clean developer experience.
From idea to production.
pnpm create @nooh-ts/template
cd my-app
pnpm install
pnpm dev
Just start coding.
Only what you use.
Node.js 18+, Bun, Deno, Serverless, etc.
Open source and community driven.
Nooh is free, open source and built for the community.