docs.json navigation:12345678910111213141516{ "navigation": { "tabs": [ { "tab": "Documentation", "groups": [ { "group": "Getting Started", "pages": ["index"] } ] }, { "tab": "API Reference", "openapi": "openapi.json" } ] } }
openapi.json (or openapi.yaml) file at the project root. If you set pagesDir, Holocron checks pagesDir first, then falls back to the project root.1234{ "tab": "API Reference", "openapi": ["openapi/v1.json", "openapi/v2.json"] }
/api/ (e.g. /api/get-users). Change the prefix with base:12345{ "tab": "API Reference", "openapi": "openapi.json", "base": "/reference" }
/reference/get-users instead."/reference" and "reference" behave the same. Set base to "" for no prefix.base to a docs/-prefixed slug like /docs/api so generated endpoints stay under /docs/* and don't collide with your real /api routes.groups or pages array to the tab. This is selective mode.guide/authentication → renders that MDX filePOST /users → renders the auto-generated endpoint page from the spec12345678910111213141516171819{ "tab": "API Reference", "openapi": "openapi.json", "groups": [ { "group": "Getting Started", "pages": [ "api/overview", "api/authentication", "POST /auth/login", "GET /users" ] }, { "group": "Orders", "pages": ["api/orders-intro", "POST /orders"] } ] }
123456789API Reference ├─ Getting Started │ ├─ Overview ← api/overview.mdx │ ├─ Authentication ← api/authentication.mdx │ ├─ POST /auth/login ← generated endpoint page │ └─ GET /users ← generated endpoint page └─ Orders ├─ Working with Orders ← api/orders-intro.mdx └─ POST /orders ← generated endpoint page
METHOD /path (case-insensitive method). To pick a specific spec when you list several, prefix it with the file name: "v2.json POST /orders"."..." entry to write a short intro and then auto-include all the remaining endpoints, grouped by tag, right after it:12345{ "tab": "API Reference", "openapi": "openapi.json", "pages": ["api/authentication", "..."] }
api/authentication guide first, then expands every endpoint not listed elsewhere into top-level tag groups (always-visible sidebar sections, exactly like dedicated mode):1234567API Reference ├─ Authentication ← api/authentication.mdx ├─ Users ← top-level group from "..." (tag: users) │ ├─ GET /users │ └─ POST /users └─ Orders ← top-level group from "..." (tag: orders) └─ POST /orders
"..." entry only expands endpoints you did not already reference explicitly, so you can pin a few important endpoints up top and let the rest fall in afterward. Only one "..." is allowed per tab.docs.json.hide: true to the route's detail object:1234567891011121314151617181920212223242526272829303132333435import { Spiceflow } from 'spiceflow' import { openapi } from 'spiceflow/openapi' import { z } from 'zod' const app = new Spiceflow() .use(openapi({ path: '/openapi.json' })) // This route appears in the spec .route({ method: 'GET', path: '/api/v0/projects', detail: { summary: 'List projects', tags: ['Projects'], }, response: { 200: z.object({ projects: z.array(z.string()) }) }, async handler() { return { projects: [] } }, }) // This route is hidden from the spec .route({ method: 'POST', path: '/api/v0/keys', detail: { hide: true, summary: 'Create API key', tags: ['Internal'], }, request: z.object({ name: z.string() }), async handler() { return { id: '123' } }, })
@hono/zod-openapi): omit the route from the OpenAPI app, or don't register it with createRouteinclude_in_schema=False on the route decoratorswagger-jsdoc): omit the JSDoc @openapi annotation from the routetags field on each operation. The sidebar shows tag groups with individual endpoint pages.