When to choose self-hosted
You already have a repo
Existing docs repo, existing collaborators, existing CI — self-hosted keeps all of that.
Full ownership
Repo lives in your GitHub org. You own everything — history, branches, protection rules, and the ability to leave us without a data export.
Monorepo
Docs live under apps/docs/ or similar alongside code. Self-hosted lets you configure a subpath root.
If none of those apply, managed repos save you the GitHub App install and a few minutes of config.
Setup
Choose your own repo in Projects → New
Pick "Connect your own GitHub repo" on the new-project screen. Creating the project takes you straight to the repo picker.
Install the NookDocs GitHub App
Pick the organization (or your personal account) and the specific repositories you want to expose. Narrow selection is strongly recommended — install on just the docs repo, not "All repositories."
Pick the repo
Select an account, then a repository from the list. Selecting one reveals the rest of the options — including Set up as monorepo, which asks for the folder your docs live in (docs, apps/docs) and limits everything we read to that path. An empty repo is also offered the starter template.
The branch is the repository's default. Change it later in Settings → Git if your team publishes from staging or a docs-specific branch.
Add `nookdocs.config.json` to the docs base directory
Create a minimal config at the docs base (the repo root for a single repo, or your monorepo subfolder):
{
"$schema": "https://nookdocs.com/schema.json",
"name": "Your Project",
"navigation": [
{
"group": "Get started",
"pages": ["introduction", "quickstart"]
}
]
}Add your content files
By default content sits flat at the docs base, next to the config. Add two .mdx files matching the nav entries above (set contentRoot if you'd rather nest them in a subfolder):
---
title: Introduction
description: Welcome to our documentation.
---
Hello world.Push and watch it deploy
git push. The webhook fires, sync runs, your site goes live at <slug>.nookdocs.site within seconds.
Resyncing everything
Each push syncs only the files that push changed, which keeps deploys fast. If your site looks out of date — say a setting was wrong while you were pushing, so those changes never landed — a later push won't fix it on its own: it only carries its own files, and the untouched ones stay as they were.
Settings → Git → Resync all pages re-reads every page from the repo and rewrites them. Your repo is the source of truth, so nothing is lost; anything saved in the editor but never committed is replaced by the committed version.
Recommended folder layout
Content sits flat at the docs base by default — no docs/ wrapper:
your-repo/ # the docs base (repo root, or a monorepo subfolder)
├── nookdocs.config.json # required, at the docs base
├── introduction.mdx
├── quickstart.mdx
├── guides/
│ ├── authentication.mdx
│ └── webhooks.mdx
├── api/
│ └── overview.mdx
├── logo/ # referenced from config.colors.logo
│ ├── light.svg
│ └── dark.svg
├── images/ # inline in MDX as 
│ └── architecture.png
├── openapi.json # optional, referenced from config.api.openapi
└── .nookignore # optional, files to exclude from syncPrefer to nest your content in a subfolder? Set contentRoot: "docs/" in nookdocs.config.json. See Content root.
Branch strategy
Most teams run a single branch (main) and treat every commit as a deploy. A few patterns for larger teams:
What we write to your repo
Every editor save lands as a Git commit signed as nookdocs-bot[bot]. Commit messages follow a predictable format so git log stays readable:
[nookdocs] update docs/guides/authentication.mdx
[nookdocs] rename docs/old-name.mdx → docs/new-name.mdx
[nookdocs] delete docs/deprecated.mdx
[nookdocs] update nookdocs.config.jsonAll commits touch files under docs/ or nookdocs.config.json by default. Nothing else.
What we never write
We never modify code, CI configs, or infrastructure files. These rules are enforced server-side, not just a policy.
Code directories:
src/,app/,packages/,lib/,apps/(except the configured docs subpath in monorepos) — untouched.CI configs:
.github/,.gitlab-ci.yml,Dockerfile,.circleci/— untouched.Node / package files:
package.json,package-lock.json,yarn.lock,pnpm-lock.yaml— untouched.Files matching
.nookignore: see .nookignore reference.
If the editor would need to touch something in this list (e.g., your docs are inside a monorepo path you haven't declared), Save fails loudly rather than silently committing.
Switch to managed hosting
Changed your mind? You can move a self-hosted project onto NookDocs managed hosting at any time — the reverse of the managed → self-hosted migration.
In Settings → Git, the connected repository card has a Host on NookDocs button. It:
Copies a snapshot of your repo
We read the current contents of your repo on the connected branch and copy them into a fresh private repo in our managed org. Your repo is never modified — we only read it.
Repoints the project
The project flips to managed mode and starts syncing from the managed repo. Your site stays live the whole time.
Leaves the GitHub App in place
The NookDocs GitHub App stays installed on your account — other projects may still use it. Remove it yourself from GitHub → Settings → Applications if you no longer need it.
After switching, edits sync from NookDocs rather than your repo. You can move back to your own repo anytime via Migrate to your GitHub on the managed repository card — see managed repos → Migrating off.
Disconnecting a repository
In Settings → Git, the connected repository card has a Disconnect button. Disconnecting:
Removes the repo from our GitHub access — we revoke this repo from the NookDocs App installation, so we genuinely lose access to it (not just a setting on our side). GitHub then notifies us via webhook to finish the cleanup.
Stops syncing — pushes to the repo no longer trigger deploys.
Removes the docs we pulled from it — the pages, file tree, parsed OpenAPI specs, and AI search index we synced are deleted, so your site stops serving content from a repo you've unlinked.
Leaves your repo untouched — we only drop our access and our synced copy. Your code, history, and files on GitHub are never modified. Reconnect any time to pull everything back in fresh.
Keeps the project — its name, subdomain, theme, custom domains, and analytics history all stay. Only the repo link and synced content are cleared.
Revoking access automatically needs the GitHub authorization you granted at connect time and only works when the App was installed on selected repositories. If the App is installed on all repositories, GitHub can't remove a single repo via API — we unlink and purge on our side, and you remove the repo (or the whole App) yourself under GitHub → Settings → Applications. We tell you when this is the case.
The same cleanup runs automatically if you uninstall the App, remove this repo from the App's access list on GitHub, or delete the repo: we detect it via webhook, unlink the project, and purge the synced docs. We never keep serving content — or holding access to — a repo you've disconnected.