Documentation Stored Only in a Database Is a Single Point of Failure
If your wiki lives entirely in a database with no export, no backup strategy, and no version history beyond “last edited by someone three months ago,” that’s not documentation — it’s a liability. A drive failure, a botched upgrade, or an accidental delete wipes it. No history, no rollback, no “who changed this and when.”
Wiki.js’s GitSync feature fixes this by syncing your wiki content to a Git repository. Your documentation becomes flat Markdown files in a repo. You get:
- Full git history on every page
- The ability to submit doc changes via pull request
- Edit from any IDE or editor, not just the wiki web interface
- Automatic backup via the repo
- CI/CD integration for automated doc updates
It’s docs-as-code, and it changes how you think about documentation.
Architecture: Push vs Pull Sync
Wiki.js GitSync works in two directions:
Pull (Git → Wiki): The wiki periodically fetches from the repo. Changes committed to the repo show up in the wiki after the sync interval. Useful if your source of truth is the repo and the wiki is just a reader.
Push (Wiki → Git): Changes made in the wiki editor get committed to the repo. The wiki is the editing interface, git is the backup.
Two-way sync: Both. Changes in the wiki push to git; changes in git pull to the wiki. This is the most flexible but requires careful merge conflict handling.
For most self-hosters: start with two-way sync and switch to push-only if you start doing a lot of direct repo edits.
Setting Up Wiki.js with Docker Compose
# docker-compose.yml
version: '3'
services:
wiki:
image: ghcr.io/requarks/wiki:2
restart: unless-stopped
ports:
- "3000:3000"
environment:
DB_TYPE: postgres
DB_HOST: db
DB_PORT: 5432
DB_NAME: wiki
DB_USER: wikijs
DB_PASS: supersecret
depends_on:
- db
volumes:
- wiki-data:/wiki/data
db:
image: postgres:15-alpine
restart: unless-stopped
environment:
POSTGRES_DB: wiki
POSTGRES_USER: wikijs
POSTGRES_PASSWORD: supersecret
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
wiki-data:
postgres-data:
docker compose up -d
# Access at http://localhost:3000
# Complete the setup wizard — set admin email/password
Configuring GitSync in the Wiki.js Admin Panel
Navigate to Administration → Storage → Git.
For GitHub:
# Create a Personal Access Token in GitHub
# Settings → Developer settings → Personal access tokens → Fine-grained tokens
# Permissions: Contents (Read and Write), Metadata (Read)
# In Wiki.js Git storage:
Authentication Type: SSH (recommended) or Basic Auth (Personal Access Token)
Repository URL: https://github.com/yourusername/wiki-docs.git
# Or SSH: git@github.com:yourusername/wiki-docs.git
Branch: main
SSH Private Key: (paste your private key)
Username: yourusername (for HTTPS)
Password/Token: your_PAT_token (for HTTPS)
For Gitea (self-hosted):
Repository URL: https://gitea.internal/youruser/wiki-docs.git
# Or SSH: git@gitea.internal:youruser/wiki-docs.git
Branch: main
Username: youruser
Password/Token: your_gitea_token
Generate a dedicated deploy key for SSH auth:
ssh-keygen -t ed25519 -C "wikijs-sync" -f ~/.ssh/wikijs_deploy -N ""
# Add the public key to your repo's deploy keys (with write access)
# Paste the private key into Wiki.js
Sync Settings
# Sync interval: how often Wiki.js polls for changes
Sync interval: 5 minutes (300 seconds)
# Sync direction:
- "Push to remote source" — wiki → git
- "Pull from remote source" — git → wiki
- "Sync bidirectionally" — both
# For the sync to work on first setup:
# Initialize the repo with at least one commit first
After saving, click “Sync Now” to test the connection.
Branch Strategy for Docs Workflows
Simple: Single Branch
Everyone edits in the wiki, changes push to main. Simple, works fine for small teams.
Wiki (editing) → Git main ← direct commits
PR Workflow: Main + Draft
Use Wiki.js to edit on a draft branch. When ready, create a PR from draft → main for review.
# In your git repo
git checkout -b draft
git push origin draft
# Configure Wiki.js GitSync to use the "draft" branch
# Set up a CI job to merge draft → main on approval
This is particularly useful for public-facing documentation where you want someone to review before publishing.
Per-Section Branches
For large teams: different sections of the wiki live on different branches. The main branch holds stable docs; contributors branch per-topic.
This gets complex fast. Only do it if you have a team that already understands the overhead.
Handling Merge Conflicts
Two-way sync can produce conflicts if the same page is edited in the wiki and in the repo simultaneously.
Wiki.js handles this with a last-write-wins strategy by default — which is fine for single-editor setups, problematic for teams.
To avoid conflicts:
- Enforce a single source of truth: Either edit in the wiki or in the repo, not both simultaneously
- Use short sync intervals (every 1-2 minutes) to reduce the conflict window
- Use webhooks to trigger immediate syncs when the repo changes
Configure a GitHub/Gitea webhook to trigger an immediate Wiki.js sync:
# In Wiki.js, the sync endpoint is:
# POST http://your-wiki:3000/admin/storage/sync
# In GitHub/Gitea webhook settings:
Payload URL: http://your-wiki:3000/admin/storage/sync
Content type: application/json
Trigger: Push events
This way, a commit to the repo immediately syncs to the wiki rather than waiting for the polling interval.
CI/CD Integration: Automated Doc Updates
The real power of GitSync: your CI/CD pipeline can update documentation automatically.
# .github/workflows/update-docs.yml
name: Update API Docs
on:
push:
branches: [main]
paths: ['openapi.yaml', 'src/**']
jobs:
update-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
repository: yourusername/wiki-docs
token: ${{ secrets.WIKI_DEPLOY_TOKEN }}
- name: Generate API docs
run: |
pip install openapi-to-markdown
openapi-to-markdown openapi.yaml > api-reference.md
- name: Commit updated docs
run: |
git config user.name "CI Bot"
git config user.email "ci@example.com"
git add api-reference.md
git diff --staged --quiet || git commit -m "Update API docs from OpenAPI spec"
git push
When this CI job runs, it updates the Markdown in the repo, which syncs to the wiki within your polling interval (or immediately via webhook). Your API docs stay in sync with your code automatically.
Markdown vs Visual Editor Mode
Wiki.js supports two editing modes:
Markdown editor: Edit raw Markdown directly. Better if you’re comfortable with Markdown, want consistent formatting, and plan to do a lot of repo-side editing.
Visual (WYSIWYG) editor: Richer formatting, more accessible for non-technical team members. The visual editor saves as Markdown under the hood, but the output can be slightly more verbose.
You can set the default editor per page type. For technical documentation, set Markdown as default. For HR policies or onboarding docs that non-engineers edit, the visual editor reduces friction.
Wiki.js vs MkDocs vs Jekyll
For “should I use Wiki.js with GitSync or just use a static site generator?”
| Feature | Wiki.js + GitSync | MkDocs/Jekyll |
|---|---|---|
| Web editing interface | Yes | No (need to commit) |
| Git-backed | Yes (via sync) | Native |
| Search | Built-in (fast) | Requires plugin |
| Access control | Per-page permissions | Static = public or nothing |
| Setup complexity | Medium | Low |
| Deployment | Docker + database | Any static host |
| Comments/discussion | Built-in | External service |
Choose Wiki.js + GitSync when: you want an editing interface for non-engineers, need per-page access control, or want comments and collaboration features.
Choose MkDocs/Jekyll when: all editors are comfortable with git, you want zero infrastructure (GitHub Pages hosting), or your docs are public and you want full CI/CD control.
Access Control in Wiki.js
Wiki.js has granular permission controls. Combined with GitSync, you can have:
Public readers: can view /docs/public/*
Editors: can edit /docs/internal/*
Admins: can edit everything, manage users
Configure in Administration → Groups:
- Create groups:
Viewers,Editors,Admins - Assign page rules: path prefix, allowed actions (read/write/manage)
- Assign users to groups
- Configure guest access (anonymous read) separately
For a documentation site where you want public content and private internal docs on the same wiki, set up two sections with different group permissions. Works well, and it’s all backed by the same git repo.
The Practical Setup Checklist
- Stand up Wiki.js + Postgres via Docker Compose
- Create a dedicated Git repo for wiki content (empty is fine)
- Generate an SSH deploy key, add public key to repo
- Configure GitSync: two-way sync, 5-minute interval, your repo URL
- Click “Sync Now” — verify it commits a test page
- Set up a webhook for immediate sync on push
- Configure CI/CD job to auto-update generated docs
- Set up access groups before inviting team members
The first sync takes a minute. After that, every page change in the wiki shows up in the repo within minutes, and every commit to the repo shows up in the wiki. Your documentation is now version-controlled, backed up, and accessible from both a nice web interface and your terminal.
That’s what documentation infrastructure should look like.