Auto-generate OpenAPI 3.0 spec from Hono routes with JSDoc - zero config, maximum automation
- Zero Configuration: Point to your main app file and auto-discover all routes
- JSDoc-Based: All metadata lives in your code via JSDoc comments
- Convention Over Configuration: Automatic prefix and name generation from filenames
- Two Modes:
- Fully Automatic (
appPath): Discover routes from main app.route()calls - Semi-Automatic (
apis): List route files with JSDoc overrides for complex setups
- Fully Automatic (
- CLI (
hono-auto-docs generate):- Extract route
AppTypedefinitions via ts-morph - Generate merged
openapi.jsonspec
- Extract route
- Full TypeScript support (TS & JS config files, inference via
defineConfig)
Metadata lives in code, not in config files.
This package enforces a JSDoc-based approach where all route metadata (@prefix, @name, @summary, @description, @tags) is defined directly in your route files. No verbose object configuration needed.
- Install
- Quick Start
- JSDoc Annotations
- Configuration Reference
- Serving the OpenAPI Docs
- CLI Usage
- Programmatic Usage
- Limitations
- Development
- Contributing
- License
# using bun
bun add -d hono-auto-docs
# using npm
npm install --save-dev hono-auto-docs
# using yarn
yarn add -D hono-auto-docsFor simple single-file route mounting patterns, just point to your main app file:
-
Create a config file (
hono-docs.ts):import { defineConfig } from "hono-auto-docs"; export default defineConfig({ tsConfigPath: "./tsconfig.json", openApi: { openapi: "3.0.0", info: { title: "My API", version: "1.0.0" }, servers: [{ url: "http://localhost:8000" }], }, outputs: { openApiJson: "./openapi.json", }, // β Single entry point - auto-discovers all routes appPath: "src/index.ts", });
-
Your main app (
src/index.ts):import { Hono } from "hono"; import { accountsApp } from "./routes/accounts"; import { transactionsApp } from "./routes/transactions"; export const app = new Hono() .route("/accounts", accountsApp) // Auto-discovered: /accounts .route("/transactions", transactionsApp); // Auto-discovered: /transactions
-
Your route files (
src/routes/accounts.ts):import { Hono } from "hono"; /** * @name Accounts */ export const accountsApp = new Hono() .get("/", (c) => { /* ... */ }) .post("/", (c) => { /* ... */ }); export type AppType = typeof accountsApp;
-
Run the CLI:
bunx hono-auto-docs generate --config ./hono-docs.ts
That's it! π
For complex mounting patterns (nested routes, conditional mounting, etc.), list route files explicitly:
import { defineConfig } from "hono-auto-docs";
export default defineConfig({
tsConfigPath: "./tsconfig.json",
openApi: {
openapi: "3.0.0",
info: { title: "My API", version: "1.0.0" },
servers: [{ url: "http://localhost:8000" }],
},
outputs: {
openApiJson: "./openapi.json",
},
// β
List route files - uses JSDoc @prefix or filename convention
apis: [
"src/routes/accounts.ts",
"src/routes/transactions.ts",
"src/routes/categories.ts",
],
});Route file with JSDoc overrides (src/routes/accounts.ts):
import { Hono } from "hono";
/**
* @prefix /accounts
* @name Accounts
*/
export const accountsApp = new Hono()
.get("/", (c) => {
/* ... */
})
.post("/", (c) => {
/* ... */
});
export type AppType = typeof accountsApp;Without @prefix, the prefix is auto-generated from the filename (accounts.ts β /accounts).
Annotate your route app export to customize OpenAPI metadata:
/**
* @prefix /custom-prefix // Optional: Override URL prefix
* @name My Route Group // Optional: Override display name
*/
export const myApp = new Hono()
.get("/", (c) => { /* ... */ });| Tag | Description | Fallback |
|---|---|---|
@prefix |
URL prefix for all routes | Filename convention (accounts.ts β /accounts) |
@name |
Display name in OpenAPI tags | Filename convention (accounts.ts β Accounts) |
Annotate individual route handlers for rich endpoint documentation:
export const accountsApp = new Hono()
/**
* List all accounts
* @summary Get all accounts for the current user
* @description Returns a paginated list of all accounts owned by the authenticated user
* @tags Accounts, Finance
*/
.get("/", (c) => {
/* ... */
})
/**
* Create a new account
* @summary Create account
* @description Creates a new financial account with the provided details
* @tags Accounts
*/
.post("/", (c) => {
/* ... */
});| Tag | Description |
|---|---|
@summary |
Short summary for the endpoint |
@description |
Detailed description |
@tags |
Comma-separated tags for categorization |
| Field | Type | Required | Description |
|---|---|---|---|
tsConfigPath |
string |
Yes | Path to your tsconfig.json |
openApi |
OpenAPIConfig |
Yes | Static OpenAPI fields (info, servers, etc.) |
outputs |
{ openApiJson: string } |
Yes | Output path for generated openapi.json |
appPath |
string |
No* | Path to main app file for auto-discovery |
apis |
string[] |
No* | Array of route file paths (for manual listing) |
preDefineTypeContent |
string |
No | Raw content injected at top of .d.ts snapshots |
* Either appPath or apis must be provided (mutually exclusive)
Install the Scalar viewer:
bun add @scalar/hono-api-referenceMount in your Hono app:
import { Hono } from "hono";
import { Scalar } from "@scalar/hono-api-reference";
import fs from "node:fs/promises";
const docsApp = new Hono()
.get("/", Scalar({ url: "/docs/openapi.json" }))
.get("/openapi.json", async (c) => {
const spec = await fs.readFile("./openapi.json", "utf-8");
return c.json(JSON.parse(spec));
});
export const app = new Hono()
.route("/docs", docsApp)
.route("/accounts", accountsApp);Visit /docs to see the interactive API documentation.
# Generate OpenAPI spec
bunx hono-auto-docs generate --config ./hono-docs.ts
# Or add to package.json scripts
{
"scripts": {
"docs": "hono-auto-docs generate --config ./hono-docs.ts"
}
}import { runGenerate } from "hono-auto-docs";
await runGenerate("./hono-docs.ts");The appPath auto-discovery only works for:
- β
Single-file method-chained
.route()calls - β Simple import β mount patterns
It does not support:
- β Nested/multi-level mounting
- β Conditional route registration
- β Non-chained registration patterns
- β Re-exported route aggregators
Solution: Use apis mode with @prefix JSDoc overrides for complex setups.
You must export AppType from each route module:
export const accountsApp = new Hono()
.get("/", (c) => { /* ... */ });
// Required!
export type AppType = typeof accountsApp;-
Clone & install dependencies:
git clone https://github.com/bacaxnot/hono-auto-docs.git cd hono-auto-docs bun install -
Build and watch:
bun run build --watch
-
Test locally via
bun linkorfile:install in a demo project.
- Fork the repo
- Create a feature branch
- Open a PR with a clear description
- Ensure code passes linting