- TypeScript 44.9%
- Rust 40.8%
- Svelte 11.5%
- CSS 1%
- JavaScript 0.9%
- Other 0.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
Some checks failed
CI / E2E (Chromium 1/2) (push) Successful in 6m46s
CI / E2E (Chromium 2/2) (push) Successful in 6m24s
CI / Web (push) Successful in 2m7s
CI / E2E (API) (push) Successful in 1m26s
CI / Rust (push) Successful in 4m49s
CI / E2E Report (push) Successful in 24s
Release / Web (push) Successful in 1m45s
iOS TestFlight / Web (push) Failing after 2m29s
Docker / Web (push) Successful in 2m44s
Docker / Rust (push) Successful in 4m51s
Docker / E2E (API) (push) Successful in 1m16s
Release / Rust (push) Successful in 7m4s
iOS TestFlight / Rust (push) Successful in 7m11s
iOS TestFlight / E2E (API) (push) Has been skipped
iOS TestFlight / E2E (Chromium 1/2) (push) Has been skipped
iOS TestFlight / E2E (Chromium 2/2) (push) Has been skipped
Release / E2E (API) (push) Successful in 1m54s
Docker / E2E (Chromium 1/2) (push) Successful in 4m19s
iOS TestFlight / E2E Report (push) Failing after 46s
iOS TestFlight / Validate TestFlight commit (push) Failing after 0s
iOS TestFlight / Build and upload to TestFlight (push) Has been skipped
Docker / E2E (Chromium 2/2) (push) Failing after 5m50s
Docker / E2E Report (push) Successful in 39s
Docker / Validate image commit (push) Failing after 0s
Docker / Build & Push Docker Image (push) Has been skipped
Release / E2E (Chromium 1/2) (push) Successful in 4m57s
Release / E2E (Chromium 2/2) (push) Successful in 5m19s
Release / E2E Report (push) Successful in 24s
Release / Validate release commit (push) Successful in 0s
Release / Classify tag (push) Successful in 2s
Release / Web Frontend (push) Successful in 35s
Release / Server (noture-server-linux-arm64) (push) Successful in 3m30s
Release / Server (noture-server-windows-amd64.exe) (push) Successful in 3m4s
Release / Server (noture-server-linux-amd64) (push) Successful in 6m32s
Release / Desktop (Windows x86_64) (push) Successful in 9m9s
Release / Desktop (Linux x86_64) (push) Successful in 10m7s
Release / Server (noture-server-macos-amd64) (push) Successful in 12m26s
Release / Server (noture-server-macos-arm64) (push) Successful in 12m4s
Release / Desktop (macOS x86_64) (push) Successful in 29m35s
Release / Desktop (macOS arm64) (push) Successful in 17m40s
Release / Create Release (push) Successful in 22s
|
||
| .forgejo | ||
| apps | ||
| crates | ||
| deploy | ||
| e2e | ||
| fixtures | ||
| fuzz | ||
| packages/editor | ||
| scripts | ||
| .dockerignore | ||
| .gitignore | ||
| .node-version | ||
| .prettierignore | ||
| .prettierrc | ||
| bench-budget.json | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| config.example.toml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint.config.js | ||
| LICENSE | ||
| package.json | ||
| perf-budget.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| rust-toolchain.toml | ||
Noture
A self-hostable note-taking app built on plain markdown files. Inspired by Obsidian's editing experience and Sublime Text's aesthetics, powered by Rust.
Highlights
- Live Preview editor — CodeMirror 6 with inline rendering of markdown, math, diagrams, and images
- Built-in sync — real-time CRDT sync across devices with no third-party service required
- E2E encryption — optional per-vault encryption (XChaCha20-Poly1305) so the server never sees plaintext
- Lightweight desktop app — native app via Tauri (~5 MB, not Electron)
- Self-hosted — run with Docker or a single binary; you own your data
- Plain markdown — flat files on disk, no proprietary format, no vendor lock-in
- Documentation publishing — publish notes or folders as websites under a path or subdomain
Quick Start
# Copy the example config
cp config.example.toml config.toml
# Start with Docker Compose
docker-compose up -d
Open http://localhost:8080 and create your first account.
Installation
Docker Compose
services:
noture:
build: .
ports:
- '8080:8080'
volumes:
- noture-data:/data
- ./config.toml:/etc/noture/config.toml:ro
environment:
NOTURE_CONFIG: /etc/noture/config.toml
NOTURE_DATA_DIR: /data
restart: unless-stopped
volumes:
noture-data:
Minimal config.toml:
bind_addr = "0.0.0.0:8080"
data_dir = "/data"
The first account you create is the admin. Registration then closes; the admin adds further accounts from the admin page.
Single Binary
Download the latest release binary for your platform, then:
export NOTURE_DATA_DIR=/var/lib/noture
export NOTURE_BIND_ADDR=0.0.0.0:8080
./noture-server
Desktop App
Download the Tauri desktop app from the releases page. Available for macOS, Windows, and Linux. The desktop app stores vaults locally and can optionally connect to a self-hosted server for sync.
Configuration
See config.example.toml for the full configuration reference.
The server reads NOTURE_CONFIG (default ./config.toml, optional). Every key
can be overridden by an environment variable named NOTURE_<KEY>. Unknown keys,
invalid values, and an unreadable config file stop the server at startup.
| Key | Default | Description |
|---|---|---|
bind_addr |
0.0.0.0:8080 |
Address and port to listen on |
data_dir |
./data |
Directory for databases, attachments, and the search index |
secure_cookies |
true |
Mark session cookies Secure (disable only for plain HTTP) |
cors_origins |
[] |
Origins allowed to make credentialed cross-origin requests |
trusted_proxies |
[] |
Reverse-proxy CIDRs whose X-Forwarded-For is trusted |
publish_base_domain |
— | Base domain for subdomain-published vaults |
public_origin |
— | Canonical origin for public links |
auth_rate_limit |
5 |
Auth attempts per client IP per minute (0 disables) |
password_hash_fast |
false |
Minimal password-hashing cost, for test environments only |
Backups
noture-server backup --data-dir /var/lib/noture --output noture-backup.tar.gz
The archive holds both databases, the attachments and a SHA-256 manifest, and
is verified before it is written. It works while the server runs. Add
--include-tantivy to keep the search index; otherwise it is rebuilt on start.
To restore, stop the server, extract the archive into an empty directory and
start the server with data_dir pointing at it.
Features
Editor
- Live Preview markdown (headings, bold, italic, code, links, images)
- WikiLinks with autocomplete and backlink tracking
- Tables, footnotes, strikethrough
- Math rendering via KaTeX (inline and display)
- Mermaid diagrams
- Obsidian-style callouts (14 types)
- Block references and transclusion (
![[note]]) - Slash command menu for block insertion
Organization
- Vaults, folders, and tags
- Graph view (D3.js)
- Backlinks panel
- Daily notes and templates
- Starred notes, recent files
- Full-text search
Sync & Collaboration
- Real-time CRDT sync via Yjs/yrs (WebSocket)
- Shared vaults with roles and invitations
Security
- Optional per-vault E2E encryption
- Argon2id password hashing
- API tokens for programmatic access
Publishing
- Publish notes or entire folders as static websites
- Path or subdomain routing (
publish_base_domain)
Import & Export
- Import from Obsidian, Joplin, and plain markdown
- Export to HTML, PDF, or ZIP
Tech Stack
| Layer | Technology |
|---|---|
| Desktop shell | Tauri v2 |
| Frontend | Svelte 5 + SvelteKit |
| Editor | CodeMirror 6 |
| Backend | Axum (Rust) |
| Sync | yrs (Rust Yjs port) |
| Storage | Flat markdown + SQLite (WAL) |
| Search | Tantivy |
| Encryption | XChaCha20-Poly1305 + PBKDF2 |
Building from Source
Prerequisites: stable Rust (rust-toolchain.toml), Node.js 24 (.node-version), pnpm 11.24.0 (pinned in package.json)
pnpm install
# Web server (produces a single binary with embedded frontend)
pnpm run build:server
# Desktop app
pnpm run tauri build
Development
pnpm run dev # SvelteKit dev server (port 5173)
pnpm run tauri dev # Desktop app with hot reload
pnpm run version:bump -- patch # Bump Noture to the next patch version
pnpm run test # Rust unit and integration tests
pnpm run test:js # Editor tests
pnpm --filter @noture/web run test # Frontend service/store tests
pnpm run test:e2e # Playwright end-to-end tests
pnpm run lint:all # Frontend + Rust lint and type checks