FAB PagePilot

GuideDocs
k
Getting Started
Home
Module
Settings
Other
Visual Editor
Documentation Sites with PagePilot

Documentation sites with PagePilot

This page explains how our documentation sites are built and why they are built that way. It is background reading, not a set of steps — if you are here to publish a page or wire up a new site, follow the setup guide in the template repository instead. What follows is the thinking behind the setup: what a "documentation site" actually is in this system, how its content is modelled, and what we gain by keeping that content out of the codebase.

The problem it solves

Most documentation sites keep every page as a file inside a code repository. It is a familiar setup, and for a small project it works well. As the documentation grows, though, a friction appears: every change to the docs — a corrected sentence, a new page, a re-ordered menu — travels through the same pipeline as a code change. It needs a branch, a review, and a deployment.
That has two costs. The people who most often need to change documentation — support, product, technical writers — usually cannot, so a developer is pulled in to make edits that have nothing to do with development. And because each change carries that overhead, small fixes get postponed, and the documentation drifts out of date.
The approach described here removes that friction by moving the content of the documentation out of the repository and into PagePilot, while leaving the presentation — the layout, the navigation, the styling — in a small front-end that rarely changes.

How a documentation site is put together

A documentation site in this system is two things working together across a network boundary.
A front-end template. A ready-made application that provides the shell of a docs site: the page layout, the top navigation, the sidebar, search, light and dark themes, and the machinery for dropping interactive components into a page. It is built once and shared across products. You clone it, point it at a PagePilot workspace, and largely leave it alone.
A PagePilot workspace. This is where the documentation actually lives. It holds the navigation menus and every page of content. The template asks the workspace for a menu and a page whenever a reader loads the site, and renders whatever comes back.
Because the two are separate, the same front-end can serve any product's documentation — only the workspace behind it differs — and the documentation can be rewritten from top to bottom without touching, rebuilding, or redeploying the front-end.

The content model: menus, pages, and sections

Three ideas describe everything in a documentation site. They are worth understanding because they are what you work with day to day in PagePilot.

Menus

A menu is a named, ordered tree that drives navigation. Each documentation site uses two: one for the sidebar, listing every page grouped by topic, and one for the top navigation, listing the main sections. Re-ordering the sidebar, renaming a group, or promoting a page is a matter of editing this tree — the navigation is data, not code.
Each entry in a menu simply points at a page by its address — its slug. There is no hidden link between the two beyond that shared piece of text, which keeps the model easy to reason about: if an entry and a page share the same slug, clicking the entry opens the page.

Pages

A page is one screen of documentation, identified by its slug — the path a reader sees in the address bar. A page belongs to a documentation group, which is how the site knows which pages make up which site, and it is either published or not. Everything else about a page is its content, which is held in sections.

Sections

A page is an ordered list of sections, and every section is one of two kinds: internal or external. The order of the list is the order they appear on the page, and a single page can mix the two freely — so an explanation and a working example can sit one after another.

Internal sections

An internal section is ordinary authored content. You build it in the PagePilot editor from blocks — headings, paragraphs, lists, tables, code samples, images — and PagePilot keeps it in two forms at once. One is the editable version the visual editor opens when someone comes back to change the page. The other is a finished, rendered version that the documentation site actually displays. You never manage those two copies yourself; PagePilot keeps them in step whenever the page is saved. The great majority of a documentation site is internal sections.

External sections

An external section has no authored content at all. It is a named empty slot — a marker that says "something goes here, and the front-end will supply it." In the PagePilot editor it shows as a locked placeholder with a note that it is managed in code; there is nothing to type into it. Each external section carries just one meaningful thing: a unique identifier, generated when the section is created. That identifier is the contract between the page and the front-end.
External sections exist because some things on a documentation page cannot be written ahead of time. They have to run in the reader's browser, against live data, at the moment the page is viewed. A console that sends a real API request and shows the real response. A pricing table that reflects the current plans. A personalised panel. A third-party embed that brings its own scripts. None of that can be expressed as static content, so instead the page leaves a labelled gap and lets the application fill it.

Executors

An executor is the component that fills an external section's gap. In an API reference, the typical executor is a small form for one endpoint: it shows a field for each parameter, builds the request as you type, sends it when you submit, and displays the status and response — a "try it" console living inside the documentation.
The front-end holds a simple lookup table that maps each external-section identifier to an executor component. When the template renders a page and reaches an external section, it reads the identifier, finds the matching executor in the table, and renders that component in place of the empty slot. If an identifier has no entry in the table, nothing is rendered — the gap simply stays empty, which is harmless. Adding a new interactive piece to the docs is therefore two small moves: place an external section on the page in PagePilot, and add one line to that lookup table pointing its identifier at a component.
Why an identifier and not a name. The identifier is an opaque value assigned when the section is created, not something derived from the endpoint or the title. That keeps the link unambiguous even if the page is renamed or the endpoint changes — the front-end always knows exactly which slot an executor belongs to. The one rule that follows: copy the identifier from the editor, don't invent one.
The division of labour is the point. The content team owns the slot — where on the page the interactive piece sits, and the prose around it. The engineering team owns the contents — what the executor actually does. Neither has to wait on the other.

How content becomes a page a reader sees

When someone opens a documentation page, the template fetches the relevant menu and the page for that address, then renders the page's sections in order. Authored sections are shown as formatted content, kept visually isolated so the documentation's styling and the site's own styling cannot interfere with each other. Interactive sections are replaced by their component.
The sidebar and the search index are both built from the same menus, so they can never fall out of step. And because a page's content is fetched each time it is viewed rather than baked in ahead of time, an edit made in PagePilot is visible on the site immediately, with no build or deployment.

Why the content lives outside the codebase

Keeping documentation content in a CMS rather than in the repository is a deliberate trade. What it buys:
  • Anyone can maintain the docs. Editing is opening a page and changing it. No local environment, no git, no review queue for a typo.
  • Changes are immediate. Publishing is a click, and the change is live. This alone tends to keep documentation far more current, because small fixes stop being deferred.
  • Navigation is managed, not coded. The structure of the site is edited in the same place as its content.
  • The site stays static and fast. Readers still get lightweight, cache-friendly pages; only the interactive parts run any code in the browser.
  • One front-end, many sites. Improvements to layout, search, or accessibility land once and benefit every product's documentation.
What it costs is a second system to understand and a network hop at request time. In practice the content model is small enough to learn in an afternoon, and the request is a cached lookup, so neither cost is heavy against the benefit of documentation that keeps pace with the product.

What this means for different people

  • Writers and support teams get a real editing tool. They draft, preview, publish, and correct without waiting on anyone.
  • Engineers own one small, stable front-end and the interactive components, and are no longer the bottleneck for wording changes.
  • Readers get documentation that is current, searchable, consistent across light and dark themes, and occasionally interactive.

How it relates to the API reference

A common use is an API reference. There the setup is partly automated: a script reads an OpenAPI or Swagger description of the API and, from it, creates a page for each endpoint and the menu entries that link to them. Each endpoint page can carry an interactive section — a small console that sends a real request — so readers can try an endpoint on the same page that documents it. The content model is exactly the same as any other documentation site; only the way the pages are first created differs.
That script can be run by a coding assistant. The template repository's setup guide is written so that an assistant — Claude, Cursor, Copilot — can carry out the whole provisioning process: read the spec, create the pages and menus, and wire up the executors. It is the quickest route from an API description to a working, browsable reference.

What you provide to set a site up

Whether the provisioning script is run by a person or by a coding assistant, it needs a few pieces of information. These are the only things asked of you — everything else is worked out from the API description or set to a sensible default and confirmed with you first.
  • The API description — a link to the OpenAPI or Swagger document for the API you want to document. It can be a raw JSON file, a Swagger UI page, or a config that lists several; the script resolves it. Everything the reference contains comes from here.
  • Your PagePilot workspace id — also called the tenant id. It identifies the workspace the pages and menus are created in. Every request the script makes is scoped to it. You will find it in your PagePilot account.
  • A PagePilot service token — the credential that authorises the script to create content in that workspace. You generate it in your PagePilot account. It is presented as a single authorisation header on each request; there is no separate sign-in step.
The workspace id and the service token both come from your own PagePilot account. Nobody can issue them for you, and an id from an example will not work — it has to be yours.

Handling the service token safely

The token grants write access to your workspace, so it needs the same care as any other secret.
  • Pass it through the environment for the one provisioning run — not typed into a file, a script, or a command that gets committed.
  • Keep it out of the front-end. The published documentation site is static and public. The token is only ever used by the setup script, never by the running site, and must never end up in the site's configuration, its bundle, or a page.
  • Rotate it if it is exposed. If it is ever pasted into a file, a chat, or a log, treat it as compromised and generate a new one. If a request comes back unauthorised, the token is wrong or has expired — replace it rather than retrying.
If you hand this to a coding assistant: give it the API link and your workspace id in the chat, but provide the service token through an environment variable it reads at run time — don't paste the token into the conversation or let it be written into any file.

Where to go next

• The template repository — the front-end, and the setup guide for wiring it to a workspace or an API spec: github.com/FAB-Builder/swagger-documentation-template
• A live example built with it: cx-docs.fabbuilder.com
• PagePilot — where the menus and pages are edited: pagepilot.fabbuilder.com

Build by FAB Builder. The source code is available on GitHub.

ContactSponsor

Translate

Choose language

Select your preferred language for this documentation.