README.md
August 24, 2026 · View on GitHub
The open-source Mintlify alternative
Nibleaf is an open-source, self-hostable documentation platform — an alternative to Mintlify and GitBook — with a rich-text editor over Markdown/MDX, first-class Arabic/RTL support, custom domains, and a free cloud beta at nibleaf.com.
Homepage · Documentation · Docs source · Quick start · Features · Self-host · Architecture · Contributing
What is Nibleaf?
Nibleaf lets you write documentation in Markdown/MDX, organize it into a navigable tree, and publish a fast, searchable, multilingual site — with versioned deploys, custom domains, per-site teams, and analytics. Run it with the guided installer or Docker Compose, or use the hosted beta. It's the docs platform you can operate end to end: no per-seat pricing for the self-hosted edition, no proprietary content format, and your content stays in your database.
- 🖋️ Rich text and Markdown, round-tripped — write visually or in raw MDX; content is Markdown end-to-end, so you're never locked into a proprietary format.
- 🌍 Multilingual & RTL-first — 12 interface languages, arbitrary BCP-47 content languages, per-language page trees, and right-to-left layout.
- 📦 Versioned publishing — every publish is an immutable snapshot; the live site is always served from a READY deployment, so readers never see a half-written page.
- 🏠 Self-hosted — Docker Compose or Coolify, bring-your-own Postgres + S3-compatible storage. Your data never leaves your infrastructure.
📸 Screenshots
The published docs site — three-column layout, instant ⌘K search, and a scroll-spy
table of contents:
The editor — Visual, Rich text, and full-canvas Markdown editing, plus a preview action that opens the saved draft in a separate tab, a drag-and-drop page tree, branches, anchored comments, and one-click publish:
✨ Features
Private customer documentation supports dedicated reader accounts, audience/page rules, and signed JWT/JWKS portal handoff. See Private reader access for integration, key rotation, caching, and recovery guidance.
- Rich editor — rich-text and raw Markdown/MDX editing with draft preview in a separate tab, a Notion-style block handle + slash menu, and a drag-and-drop, nestable page tree.
- MDX components — callouts, cards, steps, tabs, code groups, accordions, param/response fields, frames, tooltips, inline icons, KaTeX math, and Mermaid — all round-trip losslessly between visual and source. Custom components and expressions are preserved as local read-only blocks, so surrounding content and anchored comments stay editable.
- Versioned publishing — immutable snapshots; atomic roll-forward; readers never see a half-written page.
- Validated redirects — route-aware redirect graphs are flattened to canonical one-hop destinations and published atomically with the site snapshot.
- OpenAPI + Scalar — upload an OpenAPI 3.x JSON/YAML document, pull it from a public URL, or read it from the connected public GitHub/GitLab repository; published snapshots get an API Reference navigation section with schemas, generated code samples, and browser try-it.
- Branches — git-style, database-backed branches: fork, edit in isolation, and merge
into
main. - Anchored comments — Figma-style review comments pinned to the exact block.
- Tenant-safe search — built-in Orama full-text/fuzzy search remains the default and
immediate rollback; source
mainalso includes an optional Qdrant BM25+dense hybrid path, privacy-safe diagnostics, and opt-in grounded answers for English, Arabic, and mixed content. - Usage and entitlements — provider-neutral usage events, ClickHouse rollups, explicit unknown states, and advisory limits without a payment or billing claim.
- Project add-ons and integrations — audited optional capabilities, consent controls, encrypted write-only project credentials, and clear project-versus-instance ownership.
- Portable themes and read-only MCP — Harbor, Manuscript, and Signal can be exchanged as validated theme data or runnable Git repositories; scoped MCP keys expose project-bound reads.
- Multilingual & RTL — 12 interface languages, arbitrary BCP-47 content languages,
per-language page trees, RTL layout,
hreflang, and localized dashboard / editor / site chrome. - Custom domains & subdomains — guided DNS + verification, wildcard project subdomains, and host-based published-site routing.
- SEO built in — SSR, per-page canonical / Open Graph / Twitter / JSON-LD, sitemap,
robots,
hreflang, andnoindexcontrols. - Per-site teams — each site is its own workspace with role-based members (owner / admin / editor) via better-auth organizations.
- Analytics — page views, unique visitors, top pages, top searches, plus device and language breakdowns.
- Platform admin — an internal operator panel for customers, sites, deployments, and roles.
- Bring-your-own storage — any S3-compatible store (maxio, Cloudflare R2, AWS S3, Backblaze B2).
- Portable exports — snapshot-consistent Markdown ZIP, print-ready PDF, and fully static HTML, plus timezone-aware archival schedules with retention and run history.
🚧 Not built yet
Honesty over marketing — if you need these today, Nibleaf isn't there yet:
- SSO / SAML — passwordless email OTP + Google OAuth only; no enterprise SSO.
Want one of these sooner? Open or upvote an issue — github.com/lord007tn/nibleaf/issues.
OpenAPI reference setup
Open a site's Settings → API Reference, choose a navigation label and path, then provide one of these sources:
- upload or paste one JSON/YAML document (maximum 5 MB);
- a public HTTP(S) URL without embedded credentials; or
- a repository-relative file in the site's connected public GitHub/GitLab repository.
Nibleaf parses and validates OpenAPI 3.x before saving it. Validation errors identify the
first failing path in the settings toast. Public external $ref files are resolved and bundled
into the stored document: relative references work for URL and repository sources, while an
upload can use absolute public HTTP(S) references. The combined document is limited to 5 MB
and 20 external files; every fetch rejects credentials, private-network targets, unsafe
redirects, and DNS rebinding.
Publish the site after saving or refreshing a spec. The validated, self-contained document is frozen into that immutable deployment, while the editable source configuration remains available for later refreshes. Older deployments and rollbacks keep their own spec revision. Repository-backed specs currently support the public GitHub and GitLab providers; generic clone URLs can use the URL or upload option.
Scalar sends try-it requests directly from the reader's browser. Nibleaf does not provide a request proxy, prefill credentials, persist authentication, or log request secrets. Your API must allow the published documentation origin in its CORS policy. Never place live credentials or private examples in a document you intend to publish.
🚀 Quick start
On a Linux server, the pinned bootstrap downloads the v0.1.2 installer, verifies
its committed SHA-256 digest, and only then executes it. The verified installer
also verifies the release's production Compose file before it writes a mode-600
.env or starts the stack:
set -eu; d=$(mktemp -d); trap 'rm -rf "$d"' EXIT; curl -fsSLo "$d/nibleaf-install.sh" https://github.com/lord007tn/nibleaf/releases/download/v0.1.2/nibleaf-install.sh; actual=$(openssl dgst -sha256 "$d/nibleaf-install.sh"); actual=${actual##* }; [ "$actual" = "d23da907556cc31ddd4d7b3a7f62ed933106bcef8b2e9439c15e7ab71a05e59a" ] || { echo "Nibleaf installer checksum mismatch" >&2; exit 1; }; sh "$d/nibleaf-install.sh"
For manual setup, the recommended path below pulls the prebuilt image from
GHCR (ghcr.io/lord007tn/nibleaf) — nothing is compiled on your server, so it
runs fine on a small VPS:
git clone https://github.com/lord007tn/nibleaf
cd nibleaf && cp .env.production.example .env
# Edit .env — set APP_URL (your dashboard origin), the storage endpoints, and
# fresh secrets (openssl rand -hex 32). The stack fails fast if one is missing.
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
# → dashboard http://127.0.0.1:4310 (put a TLS reverse proxy in front)
Database migrations run automatically (the one-shot migrate service), and the
image tag is pinned via NIBLEAF_VERSION. Read the
backup and upgrade guide
before changing it. Open $APP_URL/sign-up and create the first
account — it's provisioned with a workspace and a starter docs project
automatically (no demo credentials are seeded in production). The full production
guide — reverse proxy, TLS, wildcard subdomains, custom-domain TLS automation,
backups, and restore testing — is in the
Nibleaf documentation.
Build from source instead (needs ~5–6 GB free RAM)
docker-compose.yml builds the whole monorepo in-container — the build needs
roughly 5–6 GB of free RAM and will OOM small servers. Prefer the pull-based
quick start above unless you're modifying the code.
cp .env.example .env
sed -i "s/^BETTER_AUTH_SECRET=.*/BETTER_AUTH_SECRET=$(openssl rand -hex 32)/" .env
docker compose up -d --build
# → dashboard http://localhost:4310 (open /sign-up to create your account)
# → API http://localhost:4311/docs
🐳 Deploy to production
- Docker Compose (recommended) — the quick start above is the production path; harden it with the production checklist (secrets, reverse proxy + TLS, wildcard docs subdomains, backups, security checklist).
- Coolify — add a Docker Compose resource pointing
at
docker-compose.coolify.yml, assign domains to theapp/admin/maxioservices (Coolify auto-generates theSERVICE_*secrets), setSITE_BASE_DOMAIN+CUSTOM_DOMAIN_CNAME_TARGET, and deploy. Pin a build withNIBLEAF_IMAGE=ghcr.io/lord007tn/nibleaf:v0.1.2. - Nibleaf Cloud — don't want to run servers? The hosted beta at nibleaf.com is free while in beta.
🏗️ Architecture
apps/
app Marketing + dashboard + docs TanStack Start + Query/Form :4310
server API Hono + better-auth :4311
worker Background jobs BullMQ :4312
admin Platform admin panel TanStack Start :4315
packages/
database Prisma schema + client (PostgreSQL)
auth better-auth (email OTP + Google OAuth + organizations)
storage S3-compatible object storage
bullmq Typed queues/workers (publish, search, email, analytics, export)
search Language-aware legacy + Qdrant hybrid retrieval contracts
qdrant Versioned collection, alias, and tenant-filtered SDK operations
clickhouse Optional analytics and usage facts/rollups
usage Provider-neutral events, periods, limits, and entitlement contracts
validators Shared Zod schemas — the server↔app contract
shared Constants, RBAC, ids, snapshot/site helpers
design-system Brand + shadcn/Base UI components
logger Pino
How publishing works — the dashboard edits Page rows (the draft). Hitting Publish
creates a Deployment and enqueues a BullMQ job; the worker builds an immutable snapshot of
the doc tree and marks the deployment READY. The public site and its search index are
served from that snapshot — so readers never see a half-written page, and rolling forward is
atomic.
How exports work — the dashboard copies the latest READY deployment into an
immutable ExportSnapshot, then queues one background ExportJob for every selected
format. Artifacts are written under the project's prefix in the configured S3-compatible
bucket; the API returns five-minute presigned download URLs only after rechecking project
membership. Static archives contain their own CSS, navigation, search index, rewritten
links, and referenced published assets. Scheduled archives use IANA timezones and a
database-backed minute dispatcher, so retries are idempotent and daylight-saving changes
keep the requested wall-clock time.
PDF rendering requires Chromium. The project Docker image installs it automatically.
Source/non-Docker workers must install a Chromium-compatible browser and set
EXPORT_CHROMIUM_PATH. Export workers also need storage credentials and the export
queue in WORKER_QUEUES when an allowlist is used. Operators can tune
EXPORT_CONCURRENCY, EXPORT_MAX_ACTIVE_PER_PROJECT, EXPORT_MAX_DAILY_PER_PROJECT,
EXPORT_MAX_PAGES, EXPORT_MAX_SNAPSHOT_BYTES, EXPORT_MAX_ASSET_BYTES,
EXPORT_MANUAL_RETENTION_DAYS, and EXPORT_DOWNLOAD_TTL_SECONDS. The nightly cleanup
job deletes expired objects and database rows; storage lifecycle rules may be added as a
defense in depth, but must not delete objects earlier than Nibleaf retention.
Same-origin auth — the dashboard proxies /api/** to the server (via Nitro), so
better-auth session cookies stay first-party with no CORS dance.
🧰 Tech stack
TanStack Start · React 19 · Hono · better-auth · Prisma · PostgreSQL · BullMQ · Dragonfly · Orama · optional Qdrant and ClickHouse · shadcn/ui (Base UI) · Tailwind CSS v4 · Zod · Pino · tsdown · Vite · Biome.
Release boundary: the integrated capabilities above are present in source
main. The checksummed installer and pinned public container remain v0.1.2 until a separate release is published. Do not treat a source merge as an image or deployment receipt.
💻 Local development
Prerequisites: Node ≥ 22, pnpm 10, Docker.
pnpm install
cp .env.example .env
# start infra only (Postgres, Dragonfly, maxio)
docker compose -f docker-compose.dev.yml up -d
# create the schema + seed a demo workspace
pnpm db:deploy # or: pnpm db:migrate (creates a new migration)
pnpm db:seed
# run server + worker + the app (add the admin app with: pnpm dev:full)
pnpm dev
| App | URL |
|---|---|
| Dashboard | http://localhost:4310 |
| API + docs | http://localhost:4311/docs |
| Worker ops | http://localhost:4312/jobs |
Demo login (after pnpm db:seed): demo@nibleaf.test / nibleafdemo123.
📜 Scripts
| Command | Description |
|---|---|
pnpm dev | server + worker + dashboard (watch mode) |
pnpm build | build every app and package |
pnpm typecheck | type-check the whole workspace |
pnpm test | run the unit test suites (Vitest) |
pnpm lint | lint + format check (Biome) |
pnpm db:migrate | create + apply a Prisma migration (dev) |
pnpm db:deploy | apply migrations (production) |
pnpm db:seed | seed the demo workspace + published site |
pnpm db:studio | open Prisma Studio |
⚙️ Configuration
All configuration is via environment variables — see
.env.production.example (production, pull-based stack)
and .env.example (local dev / source build). Storage is
S3-compatible, so swap maxio for Cloudflare R2, AWS S3, or Backblaze B2 by
changing the STORAGE_* variables. For production, set strong values for
BETTER_AUTH_SECRET, POSTGRES_PASSWORD, and STORAGE_SECRET_ACCESS_KEY, and
serve the apps behind a TLS-terminating reverse proxy. The
configuration reference
documents every production setting.
When NODE_ENV=production, the container entrypoint refuses to start (exit 1) if
BETTER_AUTH_SECRET is empty or left at a known demo default — generate one with
openssl rand -hex 32. Current product boundaries are documented in
Known limitations.
💬 Support & community
- Support guide — SUPPORT.md
- Questions & ideas — GitHub Discussions
- Bugs — GitHub Issues
- Email — support@nibleaf.com
- Security vulnerabilities — privately, please: see SECURITY.md
🤝 Contributing
Contributions are welcome! See CONTRIBUTING.md to get set up, GOVERNANCE.md for how decisions are made, and open an issue to discuss substantial changes first. Found a vulnerability? See SECURITY.md.
📄 License
Nibleaf is free software, licensed under the GNU Affero General Public License v3.0 only
(AGPL-3.0-only) — see LICENSE for the full text. Because the AGPL includes the
“network use” clause, if you run a modified version of Nibleaf as a network service you must
make your modified source available to its users. Contributions are accepted under the same
license. The “Nibleaf” name and logo are not covered by the AGPL — see
TRADEMARK.md.