Schema reference
Every field available in docs.json, with types, defaults, and constraints.
For an introduction to the file and how it fits into a deploy, see docs.json overview.
Full example
A docs.json with every field populated. Copy this and trim what you don't need.
{
"name": "Acme docs",
"description": "Documentation for Acme.",
"logo": {
"light": "/logo/light.svg",
"dark": "/logo/dark.svg",
"href": "https://acme.com"
},
"favicon": "/favicon.png",
"navigation": [
{
"tab": "Guide",
"groups": [
{
"group": "Get started",
"pages": ["quickstart", "introduction"]
},
{
"group": "Configuration",
"pages": ["configuration/docs-json", "configuration/theme"]
}
]
},
{
"group": "Reference",
"pages": ["reference/schema"]
},
{
"group": "API reference",
"openapi": "openapi.json"
}
],
"navbar": [
{ "name": "GitHub", "url": "https://github.com/acme/docs" },
{ "name": "Support", "url": "mailto:support@acme.com" }
],
"theme": {
"preset": "ocean",
"primaryOverride": "oklch(0.62 0.19 145)"
},
"api": {
"playground": {
"display": "interactive"
}
}
}Top-level fields
| Field | Type | Required | Default |
|---|---|---|---|
name | string | No | The subdomain |
description | string (≤ 160 chars) | No | None |
logo | string or { light, dark?, href? } | No | The site name |
favicon | string or { light, dark? } | No | The Bloques mark |
languages | array of language codes | No | Single language |
navigation | array of group or tab items | No | Empty sidebar |
navbar | array of { name, url, variant? } | No | No links |
theme | { preset?, primaryOverride? } | No | None |
api | { playground? } | No | None |
All nine fields are optional. A docs.json with {} is valid and renders the site with default name, no sidebar, no navbar links, and the unstyled fallback palette.
Bloques uses default as the fallback palette when
theme is unset, but you should set theme.preset explicitly so future
palette changes don't shift your site.
name
Site title. Used as the navbar brand text, the browser tab title, and the OpenGraph title for link previews.
| Property | Value |
|---|---|
| Type | string |
| Required | No |
| Default | The site's subdomain (for example, acme for acme.bloques.site) |
{ "name": "Acme docs" }description
One-sentence summary of the site. Used as the meta description and the OpenGraph description for link previews and search results.
| Property | Value |
|---|---|
| Type | string |
| Required | No |
| Max length | 160 characters |
| Default | None |
{ "description": "Documentation for Acme." }logo
Brand image shown in the top-left of the navbar, in place of the site name. Paths resolve from your repo root. See Logo and favicon.
| Property | Value |
|---|---|
| Type | string, or an object with light, dark?, and href? |
| Required | No |
| Default | The site name as text |
Logo object
| Field | Type | Required | Description |
|---|---|---|---|
light | string | Yes | Image shown in light mode. |
dark | string | No | Image shown in dark mode. Defaults to light. |
href | string | No | Where the logo links. Defaults to the site's home page. |
{ "logo": { "light": "/logo/light.svg", "dark": "/logo/dark.svg" } }favicon
Icon shown in the browser tab. Takes the same shorthand and object forms as logo, without href.
| Property | Value |
|---|---|
| Type | string, or an object with light and dark? |
| Required | No |
| Default | The Bloques mark |
{ "favicon": "/favicon.png" }languages
Languages the site serves. Adding a second code turns on the language switcher and the per-language content folders. See Internationalization.
| Property | Value |
|---|---|
| Type | array of language codes |
| Required | No |
| Supported codes | en, es |
| Default | None: the site serves one language |
English (en) is always the default language. Other codes are served under a URL prefix (/es/...).
{ "languages": ["en", "es"] }navigation
Sidebar entries. An array of items, each either a group or a tab. The two shapes are mutually exclusive: a group has group and pages, a tab has tab and groups. See Navigation for ordering, labels, and hiding pages.
| Property | Value |
|---|---|
| Type | array of group or tab items (union) |
| Required | No |
| Default | Empty array (no sidebar entries) |
Group item
| Field | Type | Required | Notes |
|---|---|---|---|
group | string | Yes | Section label in the sidebar, rendered verbatim. |
pages | array<string | group> | No | Page paths repo-relative to the docs root, without .mdx. Entries can also be nested group items. Order is the render order. |
openapi | string | No | Path to an OpenAPI spec (JSON) in the docs directory, with extension. Generates one page per operation under the group. Works on a top-level group or a group directly inside a tab. |
Provide pages, openapi, or both. A group with openapi lists its operation pages after any pages you set. See API reference overview.
{
"group": "Get started",
"pages": ["quickstart", "introduction"]
}A group entry inside pages renders as a collapsible subsection. Pages in a nested group must share a folder prefix.
{
"group": "Editor",
"pages": [
"editor/overview",
{
"group": "Components",
"pages": ["editor/components/accordion", "editor/components/callout"]
},
"editor/images"
]
}Tab item
| Field | Type | Required | Notes |
|---|---|---|---|
tab | string | Yes | Tab label in the navbar, rendered verbatim. |
groups | array of group items | Yes | Groups shown when the tab is active. Same shape as a top-level group. |
{
"tab": "API reference",
"groups": [{ "group": "Endpoints", "pages": ["api/endpoints/create"] }]
}Groups and tabs can mix in the same navigation array. Groups can nest inside
other groups, but tabs don't nest inside other tabs.
navbar
External links shown in the top navigation bar. See Navbar.
| Property | Value |
|---|---|
| Type | array of { name, url, variant? } items |
| Required | No |
| Default | Empty array (no links) |
Navbar item
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | Link label in the navbar. |
url | string | Yes | Any URL. URLs starting with http:// or https:// open in a new tab; others, the same tab. |
variant | "link" | "primary" | No | Visual weight. Defaults to "link" (plain text). "primary" renders an outlined button. |
{
"navbar": [
{ "name": "GitHub", "url": "https://github.com/acme/docs" },
{ "name": "Dashboard", "url": "https://app.acme.com", "variant": "primary" }
]
}theme
Color palette for the site. See Theme for previews and dark mode behavior.
| Property | Value |
|---|---|
| Type | { preset?, primaryOverride? } |
| Required | No |
| Default | The default preset is applied |
Theme fields
| Field | Type | Required | Notes |
|---|---|---|---|
preset | "default" | "ocean" | "emerald" | "rose" | No | Built-in palette. Each preset includes a paired dark mode. Defaults to default. |
primaryOverride | string or { light?, dark? } | No | Color replacing the preset's primary and focus ring. Accepts hex, rgb(), hsl(), oklch(), or a named color. |
{
"theme": {
"preset": "default",
"primaryOverride": "#10b981"
}
}theme.primaryOverride
A string sets the light-mode color, and Bloques derives the dark-mode shade from it. The object form sets each mode.
| Field | Type | Required | Notes |
|---|---|---|---|
light | string | No | Light-mode primary, converted and contrast-adjusted. Omit it to keep the preset's. |
dark | string | No | Dark-mode primary, rendered as written. Omit it to derive one from light. |
Bloques converts the string form and light to oklch(), drops any transparency, and adjusts lightness until the color reaches a contrast ratio of at least 3:1 against its background. A dark value renders as written.
{
"theme": {
"primaryOverride": {
"light": "#0f172a",
"dark": "#7aa2f7"
}
}
}A color Bloques can't parse falls back to the preset's primary rather than failing the deploy.
api
Settings for pages generated from an OpenAPI spec. See API reference overview.
| Property | Value |
|---|---|
| Type | { playground } |
| Required | No |
| Default | None |
api.playground
Controls the request panel at the top of every generated endpoint page.
| Field | Type | Required | Default |
|---|---|---|---|
display | "interactive" | "simple" | "none" | No | "interactive" |
proxy | boolean | No | true |
| Value | What readers see |
|---|---|
interactive | The full request form, with a Send button that calls your API from the page. |
simple | A static card with the method and path. No request form. |
none | No panel at all. |
Parameters, request and response schemas, and code samples render in every mode. Only the live-request panel changes.
{
"api": {
"playground": {
"display": "simple"
}
}
}api.playground.proxy
Send routes through Bloques by default, so your API doesn't need to allow cross-origin requests (CORS) from your docs domain.
Set proxy to false to send from the reader's browser instead. Do that when your API authenticates the browser itself — mutual TLS, a client certificate, an IP allowlist — or when you'd rather reader-supplied keys never reach our servers. Your API then has to allow CORS from your docs domain.
{
"api": {
"playground": {
"proxy": false
}
}
}Some servers are called straight from the browser either way, because Bloques can't safely proxy them: a localhost or private-network address, a plain http:// URL, or a server URL with a free-form variable in its hostname.
Validation
Bloques validates docs.json on every deploy. An invalid file fails the deploy and the site keeps serving the last good version. Common failures:
| Error | Cause |
|---|---|
description too long | Over 160 characters. |
theme.preset invalid | Value isn't one of the four preset IDs. |
api.playground.display invalid | Value isn't interactive, simple, or none. |
api.playground.proxy invalid | Value isn't true or false. |
Navigation item has neither group nor tab | Item is missing the discriminator field. |
Navigation item has both group and tab | Items are one or the other, not both. |
Group pages references a missing file | A path in pages doesn't resolve to an .mdx file in the repo. |
| Nested group has no pages | A nested group has an empty pages array. |
| Nested group pages don't share a folder | Pages inside a nested group resolve to no common folder prefix. |
| Sub-group escapes parent folder | A nested group's folder isn't a subfolder of its parent's folder. |
| Page escapes nested group folder | A page string in a nested group isn't inside the group's folder. |
A missing or invalid openapi spec doesn't fail the deploy. Bloques skips it and the rest of the site builds. See Set up an API reference for troubleshooting.