Bloques

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.

docs.json
{
  "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

FieldTypeRequiredDefault
namestringNoThe subdomain
descriptionstring (≤ 160 chars)NoNone
logostring or { light, dark?, href? }NoThe site name
faviconstring or { light, dark? }NoThe Bloques mark
languagesarray of language codesNoSingle language
navigationarray of group or tab itemsNoEmpty sidebar
navbararray of { name, url, variant? }NoNo links
theme{ preset?, primaryOverride? }NoNone
api{ playground? }NoNone

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.

PropertyValue
Typestring
RequiredNo
DefaultThe site's subdomain (for example, acme for acme.bloques.site)
docs.json
{ "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.

PropertyValue
Typestring
RequiredNo
Max length160 characters
DefaultNone
docs.json
{ "description": "Documentation for Acme." }

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.

PropertyValue
Typestring, or an object with light, dark?, and href?
RequiredNo
DefaultThe site name as text

Logo object

FieldTypeRequiredDescription
lightstringYesImage shown in light mode.
darkstringNoImage shown in dark mode. Defaults to light.
hrefstringNoWhere the logo links. Defaults to the site's home page.
docs.json
{ "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.

PropertyValue
Typestring, or an object with light and dark?
RequiredNo
DefaultThe Bloques mark
docs.json
{ "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.

PropertyValue
Typearray of language codes
RequiredNo
Supported codesen, es
DefaultNone: the site serves one language

English (en) is always the default language. Other codes are served under a URL prefix (/es/...).

docs.json
{ "languages": ["en", "es"] }

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.

PropertyValue
Typearray of group or tab items (union)
RequiredNo
DefaultEmpty array (no sidebar entries)

Group item

FieldTypeRequiredNotes
groupstringYesSection label in the sidebar, rendered verbatim.
pagesarray<string | group>NoPage paths repo-relative to the docs root, without .mdx. Entries can also be nested group items. Order is the render order.
openapistringNoPath 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.

docs.json
{
  "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.

docs.json
{
  "group": "Editor",
  "pages": [
    "editor/overview",
    {
      "group": "Components",
      "pages": ["editor/components/accordion", "editor/components/callout"]
    },
    "editor/images"
  ]
}

Tab item

FieldTypeRequiredNotes
tabstringYesTab label in the navbar, rendered verbatim.
groupsarray of group itemsYesGroups shown when the tab is active. Same shape as a top-level group.
docs.json
{
  "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.

External links shown in the top navigation bar. See Navbar.

PropertyValue
Typearray of { name, url, variant? } items
RequiredNo
DefaultEmpty array (no links)
FieldTypeRequiredNotes
namestringYesLink label in the navbar.
urlstringYesAny URL. URLs starting with http:// or https:// open in a new tab; others, the same tab.
variant"link" | "primary"NoVisual weight. Defaults to "link" (plain text). "primary" renders an outlined button.
docs.json
{
  "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.

PropertyValue
Type{ preset?, primaryOverride? }
RequiredNo
DefaultThe default preset is applied

Theme fields

FieldTypeRequiredNotes
preset"default" | "ocean" | "emerald" | "rose"NoBuilt-in palette. Each preset includes a paired dark mode. Defaults to default.
primaryOverridestring or { light?, dark? }NoColor replacing the preset's primary and focus ring. Accepts hex, rgb(), hsl(), oklch(), or a named color.
docs.json
{
  "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.

FieldTypeRequiredNotes
lightstringNoLight-mode primary, converted and contrast-adjusted. Omit it to keep the preset's.
darkstringNoDark-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.

docs.json
{
  "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.

PropertyValue
Type{ playground }
RequiredNo
DefaultNone

api.playground

Controls the request panel at the top of every generated endpoint page.

FieldTypeRequiredDefault
display"interactive" | "simple" | "none"No"interactive"
proxybooleanNotrue
ValueWhat readers see
interactiveThe full request form, with a Send button that calls your API from the page.
simpleA static card with the method and path. No request form.
noneNo panel at all.

Parameters, request and response schemas, and code samples render in every mode. Only the live-request panel changes.

docs.json
{
  "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.

docs.json
{
  "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:

ErrorCause
description too longOver 160 characters.
theme.preset invalidValue isn't one of the four preset IDs.
api.playground.display invalidValue isn't interactive, simple, or none.
api.playground.proxy invalidValue isn't true or false.
Navigation item has neither group nor tabItem is missing the discriminator field.
Navigation item has both group and tabItems are one or the other, not both.
Group pages references a missing fileA path in pages doesn't resolve to an .mdx file in the repo.
Nested group has no pagesA nested group has an empty pages array.
Nested group pages don't share a folderPages inside a nested group resolve to no common folder prefix.
Sub-group escapes parent folderA nested group's folder isn't a subfolder of its parent's folder.
Page escapes nested group folderA 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.