Skip to content
nooh
Esc
↑↓navigate↵open⌘Jpreview
On this page

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
app.ts
types.ts
error.ts
router
index.ts
di.ts
users
index.ts
[id].ts
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.

Was this page helpful?