Skip to content
Get started

The wrapper app

The Next.js application that renders a content folder — what is in it, and the build steps it runs.

The wrapper is a small Next.js application, about forty lines of it, generated by zel new app. Its only opinion is where your content lives:

src/app/[[...slug]]/page.tsx
const zellij = createZellijPages({
  contentDir: '../content',
});

That is what lets a product repository keep documentation beside the product:

payos/
├── apps/
│   ├── product/           # the application
│   └── external/          # the Zellij wrapper — no content of its own
└── docs/
    ├── external/          # the content root
    └── internal/          # not Zellij's business

The build steps it runs

@shebka/zellij ships a small binary called zellij, and the generated package.json calls it:

package.json
{
  "scripts": {
    "predev": "zellij prepare",
    "prebuild": "zellij prepare"
  }
}

Four commands, all build-time. Nothing here runs in production, and nothing here is something you type — they exist because two things have to happen before Next.js starts.

zellij preparesync-assets and search-index together — the usual choice
zellij sync-assetsCopies <content>/assets/** into public/_zellij/assets/**
zellij search-indexWrites public/_zellij/search-index.json
zellij check [dir]Validates the content folder

sync-assets exists because content lives outside the Next app and assets have to be bridged into it. It is what turns the authored path assets/hero.png into the served path /_zellij/assets/hero.png. It replaces rather than merges, so a deleted asset does not linger in public/.

search-index walks every guide folder, extracts text from the MDX, splits it per heading and writes a static JSON index. The ⌘K modal fetches that file and loads FlexSearch on first open. Section pages are excluded by design.

zellij check is the same validation zel check will run, and is available today. It exits non-zero when the folder would fail a build, so it works as a pre-commit hook or a CI step:

terminal
npx zellij check
✓ /Users/you/acme/content
  site        Acme · theme cupertino
  pages       6
  guides      1 (5 pages) · /guide
  menu        Features · Pricing · Solutions · Resources · Security
  home        /
  routes      11

  ! sections/unused.yaml is not referenced by any page in pages.yaml.

What fails a build

Invalid content fails loudly, with the file, the path inside it and what was expected. Errors are aggregated so everything can be fixed in one pass rather than one per run.

FailureBehaviour
Malformed YAML or MDXError naming the file and the parser message
Unknown section typeError listing every valid type
Unknown lucide icon nameError naming the icon and the export it looked for
Section reference with no fileError listing the sections that do exist
page: naming no page or guide folderError listing the available names
A page and a guide folder sharing a nameError naming both
Two sections on one page with the same idError — #id would be ambiguous
A nav, CTA or footer link to a nonexistent routeError naming the label and href
An anchor no section declaresError listing the anchors that page has

And the warnings, which do not stop a build:

SituationBehaviour
A section file no page referencesWarning
A guide page missing from its sidebarWarning — the page still builds
A folder with content but no _sidebar.yamlWarning — the folder is skipped
An unknown key in site.yamlWarning — forward compatibility

See also