A custom, lightweight, 100% compatible Joplin Sync Server written in Go.
The official Joplin app is named in honor of the famous composer and pianist, Scott Joplin. This custom server is named Syncopation as a play on words: it syncs your notes, and syncopation is a core musical concept that drives the ragtime rhythm Scott Joplin is known for.
- 100% Joplin Client Compatibility: Seamlessly works with official Joplin Desktop, Mobile, and CLI clients.
- End-to-End Encryption (E2EE): Fully supports transparent syncing of encrypted notes.
- Efficient Sync Engine: Handles delta syncs, sync locks, concurrency control, and batch operations.
- Lightweight & Fast: Built in Go, utilizing a single static binary and minimal memory footprint.
- Admin Web UI: Built-in administration panel using HTMX.
- Simple Deployment: Single Docker container with SQLite and Local Disk storage. No external database required.
- Backend: Go (Standard Library
net/http) - Database: SQLite (via
sqlc) - Storage: Local Filesystem
- Admin UI: Go
html/template+ HTMX
This is the recommended way to run Syncopation on your home server, NAS, or VPS.
Create a docker-compose.yml file:
services:
syncopation:
image: ghcr.io/jberlyn/syncopation:latest
container_name: syncopation
restart: unless-stopped
ports:
- "22300:22300"
volumes:
- syncopation-data:/app/data
volumes:
syncopation-data:The server stores both the SQLite database (syncopation.sqlite) and all physical note attachments inside the /app/data directory within the container.
It is crucial that you persist this directory.
- Named Volume (Example above): Best for easy management by Docker.
- Bind Mount: If you prefer storing the data in a specific folder on your host (e.g.,
- ./my-syncopation-data:/app/data), ensure the container has write permissions to that directory.
Start the server:
docker compose up -dVisit the Admin UI at http://localhost:22300/ in your browser.
Since this is a fresh install, you will be presented with a short wizard to create your initial administrator account. All accounts can be used to sync with Joplin, but only admin accounts can be used to login to the Admin UI.
It is highly recommended to place Syncopation behind a reverse proxy (like Caddy, Nginx, or Traefik) to provide HTTPS/TLS.
Important: Ensure your reverse proxy is configured to allow large request bodies (Joplin can upload large attachments) and passes standard headers.
- Nginx: Add
client_max_body_size 100M;to your server block. - Caddy: Automatically handles large bodies and SSL. A simple Caddyfile:
syncopation.yourdomain.com { reverse_proxy localhost:22300 }
- Open Joplin and go to Options > Synchronization.
- Set Sync target to Joplin Server.
- Joplin Server URL: Your server's URL (e.g.,
https://joplin.yourdomain.comorhttp://your-server-ip:22300). - Joplin Server email: The email of the account you created.
- Joplin Server password: Your password.
- Click "Check synchronization configuration".
- Go 1.25+
sqlc(for generating DB queries)
Note: Syncopation uses the pure-Go modernc.org/sqlite driver, so CGO is not required. This makes the project extremely easy to build and cross-compile!
go build -o syncopation .
./syncopationFor local development, the Go ecosystem standard Air is used for hot reloading. It automatically recompiles the binary and restarts the server whenever you modify .go or .html template files.
- Install
airglobally:
go install github.com/air-verse/air@latest- Start the development server (make sure
~/go/binis in your$PATH):
airSyncopation uses Go's standard testing package.
- Unit & Integration Tests: Run with
go test ./... - E2E Tests: Use
net/http/httptestviago test ./api/...
This project was built with the assistance of AI tooling such as Antigravity following a Research, Plan, Implement strategy.
This software is licensed under the PolyForm Noncommercial License 1.0.0. You may use, modify, and distribute this software for any non-commercial purpose (personal use, hobbies, research, etc.).
If you wish to use this software for commercial purposes (including offering it as a paid service), you must obtain explicit permission or a commercial license from the author. For full license terms, please see the LICENSE file.