๐ŸŒฟ LeafWiki

July 31, 2026 ยท View on GitHub

GitHub Stars Latest Release Backend CI Frontend CI

Self-hosted wiki. Single Go binary. SQLite + Markdown stored on disk.

For engineers and self-hosters who want structured, long-lived documentation. No Node.js, no Redis, no Postgres โ€” just a binary and a data directory.

LeafWiki

If you've looked at Wiki.js or Outline and thought "this is too much to operate for what I need" โ€” this could fit for you.

โ†’ Try it without installing: demo.leafwiki.com ยท Ctrl+E edit ยท Ctrl+S save ยท resets hourly
โ†’ If it fits, a star helps others find it.

docker run -p 8080:8080 -v ~/leafwiki-data:/app/data \
  ghcr.io/perber/leafwiki:latest \
  --jwt-secret=yoursecret --admin-password=yourpassword --allow-insecure=true

โ†’ All install options (Docker Compose, Linux installer, binary)


Table of Contents


Features

Operations:

  • Single Go binary โ€” no external database, no runtime dependencies
  • Markdown on disk โ€” page content is readable outside the app, backup is cp -r (stop the app first)
  • Runs on Linux, macOS, Windows, Raspberry Pi (x86_64 and ARM64)
  • Reverse-proxy friendly with --base-path
  • Reverse-proxy authentication via trusted HTTP header (v0.10+)
  • API keys for programmatic and agent access, admin-managed, read-only, experimental/opt-in
  • Three access modes: fully internal, public read with login-only editing, or open editing without login (see Operating Modes)
  • Roles: admin, editor, viewer

Core functionality:

  • Tree navigation โ€” explicit hierarchy, not flat note feeds
  • Manual page ordering โ€” sort order is explicit, not driven by filename (see Sorting Pages)
  • Full-text search across titles and content, with tag-based filtering
  • Tags on pages โ€” searchable and filterable across the wiki
  • Backlinks and link status per page (incoming, outgoing, broken links)
  • Built-in Markdown editor with live preview, keyboard shortcuts, and autocomplete for internal page links
  • Optimistic locking for concurrent edits
  • Markdown: tables, task lists, footnotes, callouts (:::info / :::warning), Mermaid diagrams, KaTeX math blocks ($$...$$, inline $...$ not supported), sanitized inline HTML

Customization:

  • Custom stylesheet (--custom-stylesheet, v0.8.5+)
  • Inject HTML/JS into <head> for analytics or custom CSS
  • Branding: logo, favicon, site name
  • Dark mode and mobile-friendly UI

Opt-in via feature flags:

  • Revision history (--enable-revision)
  • Automatic link rewriting when pages are renamed or moved (--enable-link-refactor)
  • Git backup โ€” push wiki content to a remote Git repository via SSH (--git-backup, v0.11.3, experimental)

Markdown import:

  • ZIP-based importer for editors and admins
  • Supports Obsidian-style wiki link rewriting on import
  • Best results with a reasonably clean folder structure; not a fully automatic converter for all source formats

Mobile:


Good fit / not a fit

Good fit:

  • Personal wikis, engineering notebooks, and runbooks
  • Internal team or homelab documentation
  • Existing Markdown or Obsidian vaults that need a structured wiki UI
  • Small teams that want tree navigation over flat note feeds
  • Self-hosted environments with low operational overhead

Probably not a fit:

  • Organizations needing complex enterprise permissions or approval workflows
  • Real-time collaborative editing
  • Teams looking for a Confluence or Notion replacement

LeafWiki is intentionally narrower than those systems. That focus is part of the value.


Prefer not to run your own server? Free hosted beta โ€” 10 spots, starting September 2026. Get a beta spot โ†’ and help shape the hosted version.


Install

Docker

docker run -p 8080:8080 \
    -v ~/leafwiki-data:/app/data \
    ghcr.io/perber/leafwiki:latest \
    --jwt-secret=yoursecret \
    --admin-password=yourpassword \
    --allow-insecure=true

--allow-insecure=true is required for plain HTTP. Omit it when serving over HTTPS (make sure your reverse proxy forwards X-Forwarded-Proto: https).

Non-root:

docker run -p 8080:8080 \
    -u 1000:1000 \
    -v ~/leafwiki-data:/app/data \
    ghcr.io/perber/leafwiki:latest \
    --jwt-secret=yoursecret \
    --admin-password=yourpassword \
    --allow-insecure=true

The data directory must be writable by the specified user.

Docker Compose

services:
  leafwiki:
    image: ghcr.io/perber/leafwiki:latest
    container_name: leafwiki
    user: 1000:1000
    ports:
      - "8080:8080"
    environment:
      - LEAFWIKI_JWT_SECRET=yourSecret
      - LEAFWIKI_ADMIN_PASSWORD=yourPassword
      - LEAFWIKI_ALLOW_INSECURE=true  # Required for plain HTTP. Omit for HTTPS (ensure `X-Forwarded-Proto: https` is forwarded).
    volumes:
      - ${HOME}/leafwiki-data:/app/data
    restart: unless-stopped

Linux installer

sudo /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/perber/leafwiki/main/install.sh)"

Installs LeafWiki as a system service. Tested on Ubuntu, Debian, and Raspbian.

Update:

sudo /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/perber/leafwiki/main/update.sh)"

Only works if you installed with the script above. Not compatible with Docker or binary installs.

Non-interactive mode:

cp .env.example .env
# Edit .env with your configuration
sudo ./install.sh --non-interactive --env-file ./.env

Security: in interactive mode, environment variables are written in plain text to /etc/leafwiki/.env. Restrict access to that file.

Deployment examples:

Binary

chmod +x leafwiki
./leafwiki --jwt-secret=yoursecret --admin-password=yourpassword --allow-insecure=true

The server binds to 127.0.0.1:8080 by default. To expose it on the network:

./leafwiki --jwt-secret=yoursecret --admin-password=yourpassword --host=0.0.0.0 --allow-insecure=true

Default data directory is ./data. Change with --data-dir.

Reset admin password

./leafwiki reset-admin-password

Operating Modes

LeafWiki supports three access modes. Pick the one that matches your environment:

1. Internal wiki โ€” login required (default)

All access requires authentication. Nobody can read or edit without a valid account. This is the default behavior when no access flags are set.

./leafwiki --jwt-secret=yoursecret --admin-password=yourpassword

Use this for team-internal wikis or homelab setups where content should stay private.

2. Public read, login required for editing

Anyone can browse the wiki without logging in. Only authenticated users with an editor or admin role can make changes.

./leafwiki --jwt-secret=yoursecret --admin-password=yourpassword --public-access=true

Use this for open documentation or project wikis where readers don't need accounts, but you still want to control who can edit.

3. No login โ€” everyone can read and edit (--disable-auth)

Authentication is completely disabled. Anyone who can reach the server can read and edit all pages.

./leafwiki --disable-auth --host=127.0.0.1

โš ๏ธ Only use this on trusted internal networks or local setups. Never expose a --disable-auth instance to the public internet.


Dev Setup

Stack: Go ยท React (Vite) ยท SQLite

git clone https://github.com/perber/leafwiki.git
cd leafwiki

Terminal 1 โ€” Frontend:

cd ui/leafwiki-ui
npm install
npm run dev

Terminal 2 โ€” Backend:

cd cmd/leafwiki
go run . --jwt-secret=yoursecret --allow-insecure=true --admin-password=yourpassword

Vite starts on http://localhost:5173. The backend binds to 127.0.0.1 by default.

See CONTRIBUTING.md for contribution guidelines.


Configuration

Required

FlagDescription
--jwt-secretSecret for signing JWTs. Keep it secure.
--admin-passwordInitial admin password (only applied if no admin exists yet).

Optional admin identity

FlagDescriptionDefault
--admin-usernameInitial admin username (only applied if no admin exists yet).admin
--admin-emailInitial admin email (only applied if no admin exists yet).admin@localhost

For plain HTTP: add --allow-insecure=true so login and CSRF cookies work.

CLI Flags

FlagDescriptionDefaultSince
--hostHost/IP the server binds to127.0.0.1โ€“
--portPort the server listens on8080โ€“
--unix-socketUnix domain socket path; overrides --host and --port""v0.11.3
--data-dirDirectory where data is stored./dataโ€“
--admin-usernameInitial admin username (only applied if no admin exists yet)adminv0.12.0
--admin-emailInitial admin email (only applied if no admin exists yet)admin@localhostv0.12.0
--public-accessAllow public read-only accessfalseโ€“
--base-pathURL prefix for reverse proxy setups (e.g. /wiki)""v0.8.2
--allow-insecureโš ๏ธ Enables HTTP for auth cookies (required for plain HTTP)falsev0.7.0
--disable-authโš ๏ธ Disable all authentication (internal networks only)falsev0.7.0
--access-token-timeoutAccess token duration (e.g. 24h, 15m)15mv0.7.0
--refresh-token-timeoutRefresh token duration (e.g. 168h)168hv0.7.0
--max-asset-upload-sizeMax upload size (e.g. 50MiB, 52428800)50MiBv0.8.5
--custom-stylesheetPath to a .css file inside the data dir""v0.8.5
--inject-code-in-headerRaw HTML/JS injected into <head>""v0.6.0
--hide-link-metadata-sectionHide backlinks and link status panelfalseโ€“
--enable-revisionEnable revision historyfalsev0.9.0
--enable-link-refactorEnable link rewriting on rename/movefalsev0.9.0
--max-revision-historyMax revisions per page; 0 = unlimited100v0.9.0
--revision-coalesce-windowWindow for coalescing rapid successive auto-save revisions by the same author; 0 = disabled5mv0.11.0
--enable-http-remote-userEnable reverse-proxy auth via HTTP headerfalsev0.10.0
--http-remote-user-header-nameHeader name carrying the username or email from the proxyRemote-Userv0.10.0
--trusted-proxy-ipsTrusted proxy IPs/CIDRs for remote-user header""v0.10.0
--login-urlRedirect to an external URL instead of the built-in login form""v0.12.0
--logout-urlRedirect to an external URL after logout""v0.12.0
--http-remote-user-logout-urlโš ๏ธ Deprecated, use --logout-url instead""v0.10.0
--disable-request-logSuppress per-request HTTP access log linesfalsev0.10.1
--log-formatLog output format: text or jsontextv0.12.0
--totp-encryption-keyKey to encrypt per-user TOTP secrets at rest (min 32 bytes); required only once a user enables TOTP""v0.12.0
--enable-metricsEnable the Prometheus /metrics endpoint on a separate listenerfalsev0.12.0
--metrics-hostHost/IP for the metrics listener127.0.0.1v0.12.0
--metrics-portPort for the metrics listener9091v0.12.0
--snapshotEnable full backup snapshots (ZIP incl. the SQLite database)truev0.12.0
--snapshot-intervalSnapshot interval (e.g. 24h, 6h); 0 = manual-only24hv0.12.0
--snapshot-retentionNumber of most recent snapshots to keep; <= 0 = keep all10v0.12.0
--snapshot-dirDirectory to store snapshot ZIPs in<data-dir>/snapshotsv0.12.0
--restore-upload-max-sizeMax size for an uploaded backup ZIP to restore from500MiBv0.12.0
--git-backupโš—๏ธ Enable git backup to a remote repositoryfalsev0.11.3
--git-backup-remoteโš—๏ธ SSH remote URL for git backup (e.g. git@github.com:user/repo.git)""v0.11.3
--git-backup-branchโš—๏ธ Branch to push tomainv0.11.3
--git-backup-ssh-keyโš—๏ธ Raw SSH private key (prefer env var)""v0.11.3
--git-backup-ssh-key-pathโš—๏ธ Path to SSH private key file""v0.11.3
--git-backup-ssh-known-hostsโš—๏ธ Path to known_hosts for MITM protection""v0.11.3
--git-backup-author-nameโš—๏ธ Git commit author nameLeafWiki Backupv0.11.3
--git-backup-author-emailโš—๏ธ Git commit author emailbackup@leafwiki.localv0.11.3
--git-backup-intervalโš—๏ธ Backup interval (e.g. 60m, 2h); 0 = manual-only60mv0.11.3

Docker image default: LEAFWIKI_HOST is set to 0.0.0.0 automatically by the container entrypoint if neither --host nor LEAFWIKI_HOST is provided.

Environment Variables

VariableDescriptionDefaultSince
LEAFWIKI_HOSTHost/IP address127.0.0.1โ€“
LEAFWIKI_PORTPort8080โ€“
LEAFWIKI_UNIX_SOCKETUnix domain socket path; overrides host/port""v0.11.3
LEAFWIKI_DATA_DIRData directory path./dataโ€“
LEAFWIKI_ADMIN_PASSWORDInitial admin password (required)โ€“โ€“
LEAFWIKI_ADMIN_USERNAMEInitial admin username (only applied if no admin exists yet)adminv0.12.0
LEAFWIKI_ADMIN_EMAILInitial admin email (only applied if no admin exists yet)admin@localhostv0.12.0
LEAFWIKI_JWT_SECRETJWT signing secret (required)โ€“โ€“
LEAFWIKI_PUBLIC_ACCESSAllow public read-only accessfalseโ€“
LEAFWIKI_BASE_PATHURL prefix for reverse proxy""v0.8.2
LEAFWIKI_ALLOW_INSECUREโš ๏ธ HTTP auth cookiesfalsev0.7.0
LEAFWIKI_DISABLE_AUTHโš ๏ธ Disable authenticationfalsev0.7.0
LEAFWIKI_ACCESS_TOKEN_TIMEOUTAccess token duration15mv0.7.0
LEAFWIKI_REFRESH_TOKEN_TIMEOUTRefresh token duration168hv0.7.0
LEAFWIKI_MAX_ASSET_UPLOAD_SIZEMax upload size50MiBv0.8.5
LEAFWIKI_CUSTOM_STYLESHEETPath to .css file inside data dir""v0.8.5
LEAFWIKI_INJECT_CODE_IN_HEADERHTML/JS injected into <head>""v0.6.0
LEAFWIKI_HIDE_LINK_METADATA_SECTIONHide backlinks and link status panelfalseโ€“
LEAFWIKI_ENABLE_REVISIONRevision historyfalsev0.9.0
LEAFWIKI_ENABLE_LINK_REFACTORLink rewriting on rename/movefalsev0.9.0
LEAFWIKI_MAX_REVISION_HISTORYMax revisions per page; 0 = unlimited100v0.9.0
LEAFWIKI_REVISION_COALESCE_WINDOWWindow for coalescing rapid successive auto-save revisions; 0 = disabled5mv0.11.0
LEAFWIKI_ENABLE_HTTP_REMOTE_USERReverse-proxy auth via headerfalsev0.10.0
LEAFWIKI_HTTP_REMOTE_USER_HEADER_NAMEUsername or email header from proxyRemote-Userv0.10.0
LEAFWIKI_TRUSTED_PROXY_IPSTrusted proxy IPs/CIDRs""v0.10.0
LEAFWIKI_LOGIN_URLRedirect to an external URL instead of the login form""v0.12.0
LEAFWIKI_LOGOUT_URLRedirect to an external URL after logout""v0.12.0
LEAFWIKI_HTTP_REMOTE_USER_LOGOUT_URLโš ๏ธ Deprecated, use LEAFWIKI_LOGOUT_URL instead""v0.10.0
LEAFWIKI_DISABLE_REQUEST_LOGSuppress per-request HTTP access log linesfalsev0.10.1
LEAFWIKI_LOG_FORMATLog output format: text or jsontextv0.12.0
LEAFWIKI_LOG_LEVELLog level: debug, info, warn, error (env-var only, no CLI flag)infov0.8.0
LEAFWIKI_TOTP_ENCRYPTION_KEYKey to encrypt per-user TOTP secrets at rest (min 32 bytes)""v0.12.0
LEAFWIKI_ENABLE_METRICSEnable the Prometheus /metrics endpointfalsev0.12.0
LEAFWIKI_METRICS_HOSTHost/IP for the metrics listener127.0.0.1v0.12.0
LEAFWIKI_METRICS_PORTPort for the metrics listener9091v0.12.0
LEAFWIKI_SNAPSHOTEnable full backup snapshotstruev0.12.0
LEAFWIKI_SNAPSHOT_INTERVALSnapshot interval; 0 = manual-only24hv0.12.0
LEAFWIKI_SNAPSHOT_RETENTIONNumber of most recent snapshots to keep; <= 0 = keep all10v0.12.0
LEAFWIKI_SNAPSHOT_DIRDirectory to store snapshot ZIPs in<data-dir>/snapshotsv0.12.0
LEAFWIKI_RESTORE_UPLOAD_MAX_SIZEMax size for an uploaded backup ZIP to restore from500MiBv0.12.0
LEAFWIKI_GIT_BACKUPโš—๏ธ Enable git backupfalsev0.11.3
LEAFWIKI_GIT_BACKUP_REMOTEโš—๏ธ SSH remote URL""v0.11.3
LEAFWIKI_GIT_BACKUP_BRANCHโš—๏ธ Branch to push tomainv0.11.3
LEAFWIKI_GIT_BACKUP_SSH_KEYโš—๏ธ Raw SSH private key (preferred over path)""v0.11.3
LEAFWIKI_GIT_BACKUP_SSH_KEY_PATHโš—๏ธ Path to SSH private key file""v0.11.3
LEAFWIKI_GIT_BACKUP_SSH_KNOWN_HOSTSโš—๏ธ Path to known_hosts file""v0.11.3
LEAFWIKI_GIT_BACKUP_AUTHOR_NAMEโš—๏ธ Git commit author nameLeafWiki Backupv0.11.3
LEAFWIKI_GIT_BACKUP_AUTHOR_EMAILโš—๏ธ Git commit author emailbackup@leafwiki.localv0.11.3
LEAFWIKI_GIT_BACKUP_INTERVALโš—๏ธ Backup interval (e.g. 60m); 0 = manual-only60mv0.11.3

Custom Stylesheet

Place a .css file inside your data directory and pass its path:

./leafwiki \
  --data-dir=./data \
  --custom-stylesheet=custom.css \
  --jwt-secret=yoursecret \
  --admin-password=yourpassword
  • File must exist at ./data/custom.css
  • Served as /custom.css (or ${base-path}/custom.css with --base-path)
  • The endpoint is publicly accessible

Reverse-Proxy Authentication

Available since v0.10.0. Use when an upstream proxy authenticates users and forwards the username or email via HTTP header.

./leafwiki \
  --jwt-secret=yoursecret \
  --admin-password=yourpassword \
  --enable-http-remote-user=true \
  --http-remote-user-header-name=X-Forwarded-User \
  --trusted-proxy-ips=127.0.0.1,172.18.0.0/16 \
  --login-url=https://auth.example.com/login \
  --logout-url=https://auth.example.com/logout
  • Only trusts the header from IPs listed in --trusted-proxy-ips
  • If the forwarded username or email doesn't match a LeafWiki user, the request is rejected
  • Do not enable without configuring --trusted-proxy-ips
  • --login-url and --logout-url are independent, optional redirect targets โ€” set either or both to send users to an external IdP instead of the built-in login form / to redirect after logout
  • --login-url, --logout-url, and --user-management-url must all start with http:// or https://; the server refuses to start otherwise (relative paths are not accepted for any of them)
  • โš ๏ธ --login-url takes effect regardless of --enable-http-remote-user and has no in-app bypass: once set, every unauthenticated visit (including /login itself) redirects to it immediately. Double-check the URL before setting it โ€” a wrong or unreachable value locks all users, including admins, out of the built-in login form
  • --http-remote-user-logout-url (v0.10.0) is deprecated; use --logout-url instead. It still works as a fallback when --logout-url/LEAFWIKI_LOGOUT_URL isn't set, but a deprecation warning is logged

Unix Socket (v0.11.3)

Use --unix-socket when LeafWiki should listen on a local unix domain socket instead of TCP.

./leafwiki \
  --unix-socket=/run/leafwiki/leafwiki.sock \
  --data-dir=./data \
  --jwt-secret=yoursecret \
  --admin-password=yourpassword
  • --unix-socket overrides --host and --port
  • LeafWiki still serves normal HTTP; a reverse proxy such as Nginx or Caddy connects to the socket
  • If a stale socket file exists from a previous run, LeafWiki removes it before listening
  • New socket files are created with permissions 0660
  • On Windows, unix sockets are not supported and LeafWiki returns a startup error if this option is used

Git Backup (v0.11.3, experimental)

Experimental โ€” This feature is new and may change in future releases. Test it thoroughly before relying on it for critical data.

Git Backup pushes wiki content to a remote Git repository via SSH on a configurable interval. It covers the root/ (pages) and assets/ directories. Database files (.db, .db-wal, etc.) and runtime files are excluded via .gitignore.

Backups run automatically on a configurable interval and can also be triggered manually from the Git Content Backup page.

CLI flags (v0.11.3+):

FlagDescriptionDefault
--git-backupEnable git backupfalse
--git-backup-remoteSSH remote URL (e.g. git@github.com:user/repo.git)""
--git-backup-branchBranch to push tomain
--git-backup-ssh-keyRaw SSH private key (prefer env var)""
--git-backup-ssh-key-pathPath to SSH private key file""
--git-backup-ssh-known-hostsPath to known_hosts for MITM protection""
--git-backup-author-nameGit commit author nameLeafWiki Backup
--git-backup-author-emailGit commit author emailbackup@leafwiki.local
--git-backup-intervalBackup interval (e.g. 60m, 2h); 0 = manual-only60m

Environment variables:

VariableDescription
LEAFWIKI_GIT_BACKUPEnable git backup
LEAFWIKI_GIT_BACKUP_REMOTESSH remote URL
LEAFWIKI_GIT_BACKUP_BRANCHBranch to push to
LEAFWIKI_GIT_BACKUP_SSH_KEYRaw SSH private key
LEAFWIKI_GIT_BACKUP_SSH_KEY_PATHPath to SSH private key file
LEAFWIKI_GIT_BACKUP_SSH_KNOWN_HOSTSPath to known_hosts file
LEAFWIKI_GIT_BACKUP_AUTHOR_NAMEGit commit author name
LEAFWIKI_GIT_BACKUP_AUTHOR_EMAILGit commit author email
LEAFWIKI_GIT_BACKUP_INTERVALBackup interval

Example (Docker Compose):

environment:
  - LEAFWIKI_GIT_BACKUP=true
  - LEAFWIKI_GIT_BACKUP_REMOTE=git@github.com:youruser/yourwiki-backup.git
  - LEAFWIKI_GIT_BACKUP_BRANCH=main
  - LEAFWIKI_GIT_BACKUP_SSH_KEY=${LEAFWIKI_GIT_BACKUP_SSH_KEY}  # from .env file
  - LEAFWIKI_GIT_BACKUP_INTERVAL=60m

Notes:

  • --git-backup-remote is required when using SSH push. The remote must be an SSH URL (git@... or ssh://...).
  • Either --git-backup-ssh-key or --git-backup-ssh-key-path is required when a remote is configured. Prefer the environment variable to avoid the key appearing in process listings.
  • --git-backup-ssh-known-hosts is optional but recommended. If not set, LeafWiki falls back to ~/.ssh/known_hosts. If that file does not exist either (common in containers), SSH host key verification is disabled โ€” leaving connections open to MITM attacks. Set this flag explicitly in production.
  • If the remote diverges (e.g. someone pushed directly to the backup branch), LeafWiki will stop auto-pushing and show a Conflict โ€” remote diverged warning in the UI. Click Force Push in the UI to overwrite the remote with the current local backup history. Your wiki content is never lost โ€” the local backup repo is always authoritative.
  • This backs up content only โ€” the SQLite database is not included. For a full backup, use your data directory (cp -r with the app stopped).

Security

Enabled by default since v0.7.0:

  • Secure, HttpOnly cookies for session handling
  • CSRF protection on all state-changing requests
  • Rate limiting on auth endpoints
  • Role-based access: admin, editor, viewer

--disable-auth removes all authentication. Only use for local development, trusted internal networks, or isolated environments.

# Safe local-only example:
./leafwiki --disable-auth --host=127.0.0.1

For most setups, prefer --public-access for read-only public access and the viewer role for restricted accounts.

Operations notes

  • Default bind: 127.0.0.1 (binary) / 0.0.0.0 (Docker image)
  • Default data dir: ./data (binary) / /app/data (container)
  • Defaults are intentionally conservative โ€” a fresh install does not become network-exposed by accident

Keyboard Shortcuts

ActionShortcut
Edit modeCtrl + E / Cmd + E
SaveCtrl + S / Cmd + S
SearchCtrl + Shift + F / Cmd + Shift + F
Navigation paneCtrl + Shift + E / Cmd + Shift + E
Go to pageCtrl + Alt + P / Cmd + Option + P
BoldCtrl + B / Cmd + B
ItalicCtrl + I / Cmd + I
Headline 1โ€“3Ctrl + Alt + 1โ€“3 / Cmd + Alt + 1โ€“3

Ctrl+V / Cmd+V for pasting images and files works in the editor.
Esc closes modals, dialogs, and edit mode.


External Edits & Resync

If you edit Markdown files directly on disk โ€” a text editor, Git, a script, a bulk import โ€” LeafWiki won't pick up the changes on its own. Trigger a resync one of two ways:

  • Admin UI: trigger it manually from the maintenance/admin settings page, with live progress across four phases (tree, links, tags, search).
  • OS signal: send SIGUSR1 or SIGHUP to the running process (e.g., from a git post-receive hook or a cron job) โ€” no restart needed.

Both paths share the same resync job, so either way you get the same consistent result. This is separate from .leafwikiignore changes, which are only read at startup.

New files without a leafwiki_id: every page's identity lives in a leafwiki_id field in its own frontmatter, not in its filename or path โ€” that's what lets pages survive renames and moves without losing their identity. If you add a .md file yourself (not created through the app) and it has no leafwiki_id yet, the next resync generates one and writes it back into the file on disk. This is automatic and requires no action from you, but it does mean the file changes on disk after the resync โ€” worth knowing if you manage root/ with your own separate Git workflow (outside LeafWiki's built-in Git Backup), since that ID write-back will show up as an extra diff you didn't make yourself.


Sorting Pages

Page order in LeafWiki is explicit and manual โ€” it does not follow filename or alphabetical order automatically. By default, pages appear in the order they were created.

LeafWiki is not a file browser. The tree reflects the structure you define, and the order you set is the order your readers see.

To reorder the pages inside a section or under a parent page:

  1. Hover over the section or page in the sidebar tree to reveal the action buttons
  2. Click the โ‹ฎ (more actions) button
  3. Select Sort Section Children or Sort Page Children

Sort context menu

The sort dialog lets you drag items into position, use the โ†‘ โ†“ arrow buttons, or jump to alphabetical order with A โ†’ Z / Z โ†’ A. Click Save to apply.

Sort dialog

Sorting is per level โ€” the order of a section's direct children is independent of deeper nested items.


Support this project

If it's useful to you:

Need help deploying LeafWiki for your team? Business support & setup โ†’


Contributing

Contributions, discussions, and feedback are welcome.
Open an issue or start a discussion on GitHub. Follow the repository to get notified about new releases.