Project structure
A walkthrough of every file and folder in a Nooh project and what each one does.
A Nooh project is a regular TypeScript project with a few special directories. Nooh discovers your routes and dependencies by reading the filesystem, so the layout of those directories is what drives your API.
Typical layout
- nooh.config.ts
- src/
- index.ts
- middleware/
- logger.ts
- deps/
- db.ts
- routes/
- index.get.ts
- users/
- $.ts
- index.get.ts
- [id].get.ts
- .nooh/
- app.ts
- router/
- index.ts
- users/
- index.ts
- [id].ts
File-by-file
nooh.config.ts
The project configuration. This is the only file Nooh requires. It tells the compiler where your routes and dependency containers live:
import { config } from "@nooh-ts/nooh";
export default config({
routes: "src/routes", // directory where Nooh looks for routes
dependencies: "src/deps", // directory where Nooh looks for containers
});
You can also pass a Hono Env type parameter to propagate environment types across the entire generated application:
import { config } from "@nooh-ts/nooh";
export interface App {
Variables: {
user: User;
};
}
export default config<App>({
routes: "src/routes",
dependencies: "src/deps",
});
Route files
Every .ts file inside your routes directory is a route. The filename encodes the HTTP method and the path:
| File | Route |
|---|---|
routes/index.get.ts |
GET / |
routes/users/index.get.ts |
GET /users |
routes/users/[id].get.ts |
GET /users/:id |
routes/users/[id].post.ts |
POST /users/:id |
A route file exports a default value produced by the generated handler factory:
// src/routes/users/[id].get.ts
import { get } from "@router/users/[id]";
export default get((c) => {
const id = c.req.param("id");
return c.json({ id });
});
Group files ($.ts)
A $.ts file inside a directory applies middleware and configuration to all routes in that directory and its subdirectories:
// src/routes/users/$.ts
import logger from "@middleware/logger";
import { group } from "@nooh-ts/nooh";
export default group({
middleware: [logger],
});
Dependency containers
Files inside your dependencies directory export containers — objects that declare services and their scopes:
// src/deps/db.ts
import { container, singleton } from "@nooh-ts/nooh";
export default container({
connection: singleton(() => new Database(process.env.DATABASE_URL)),
});
Entry point (src/index.ts)
Your Hono entry point. Nooh generates a .nooh/app.ts that is a standard Hono app; you import and re-export it:
// src/index.ts
import app from "../.nooh/app";
export default app;
.nooh/ (generated)
The output directory. This is generated by the compiler — do not edit it by hand, and add it to .gitignore if you prefer a clean repository. Every file inside it is plain TypeScript that you can inspect.
.nooh
router
users
| File | Purpose |
|---|---|
app.ts |
The root Hono application — import this from your entry point. |
types.ts |
Re-exports your App type so all generated modules stay in sync. |
error.ts |
Runtime helpers for response validation. |
router/*.ts |
One typed handler factory per route path. |
router/di.ts |
Dependency injection runtime helpers. |