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.x-holocron to an OpenAPI operation to override its generated page metadata, insert MDX content, or choose its URL.12345678910111213141516paths: /users: post: summary: Create user x-holocron: metadata: title: Create a new user sidebarTitle: Create user description: Add a user to the current organization. content: | <Badge color="blue">1 Credit</Badge> <Note> User email addresses must be unique. </Note> href: /api-reference/users/create
metadata object supports title, sidebarTitle, and description. The content field accepts Markdown and Holocron MDX components. Holocron renders it before the generated endpoint header, description, authorization, parameters, and request fields.href must be an internal path without a query string or hash. It replaces the normal method-and-path slug and does not use the tab's base prefix.x-holocron for new specifications. It is the canonical extension and can gain Holocron-specific options in future releases.x-mint as a compatibility alias for the same page overrides. Existing Mintlify specifications work without renaming the extension.12345678paths: /users: post: x-mint: metadata: title: Create a new user sidebarTitle: Create user content: '<Badge color="blue">1 Credit</Badge>'
title, sidebarTitle, and description directly inside the extension. Holocron supports this legacy shape too. When direct fields and metadata both define a value, metadata wins.x-holocron wins field by field. Missing or invalid x-holocron fields fall back to valid x-mint values.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.