Sake is a self-hostable reading stack built around a Svelte web app and a KOReader plugin.
It keeps your library, reading progress, and device sync in one place, with optional search/download providers for importing books into your collection.
This repository has two important layers:
sake/- the actual SvelteKit app (Svelte 5+SvelteKit+Bun)koreaderPlugins/- the KOReader plugin shipped by the appdocs/- shared project documentation and screenshots
If you are working on the app itself, run app commands from sake/.
- Manage a personal library with metadata, shelves, ratings, and reading state
- Sync KOReader devices with the web app
- Keep reading progress and sidecar data in sync
- Import books through provider-based search and download flows
- Serve KOReader plugin updates from the same stack
- Run on libSQL plus S3-compatible object storage
Use this if you want the easiest all-in-one setup for local or personal self-hosting.
It uses:
docker-examples/docker-compose.prebuilt.selfhost.yamlfor the published image pathdocker-compose.selfhost.yamlat the repository rootsake/.env.docker.selfhosted- a file-backed libSQL database
- SeaweedFS as the S3-compatible storage example
- a one-shot migrator container that applies schema changes before the app starts
From the repository root with the prebuilt image:
docker compose -f docker-examples/docker-compose.prebuilt.selfhost.yaml upOr build it locally from source:
docker compose -f docker-compose.selfhost.yaml up --buildThen open http://localhost:5173.
Data is persisted under:
./.data/selfhost/libsql./.data/selfhost/seaweedfs
Use this if you want to run only the Sake containers but keep your database and object storage elsewhere, for example:
- Turso for libSQL
- Cloudflare R2 or another S3-compatible storage provider
Edit sake/.env, then start from the repository root with the prebuilt image:
docker compose -f docker-examples/docker-compose.prebuilt.yaml upOr build it locally from source:
docker compose up --buildThis Compose stack runs:
sake-migratorfirst (bun run db:migrate)sakeafter the migration succeeds
Then open http://localhost:5173.
Use this if you are developing the app locally and already have a reachable database and S3-compatible storage.
Configure sake/.env, then run from sake/:
bun install
bun run db:migrate
bun run devThen open http://localhost:5173.
If you are not using Docker Compose, run bun run db:migrate before first boot and again after future schema changes.
Published images live at ghcr.io/sudashiii/sake.
Available tags:
latest<version>where<version>matches the existing CalVer without thewebapp/vprefixsha-<shortsha>
Example:
SAKE_IMAGE=ghcr.io/sudashiii/sake:2026.03.28.1 docker compose -f docker-examples/docker-compose.prebuilt.yaml upCopy sake/.env.example to sake/.env and fill in the values you need.
LIBSQL_*- database connectionS3_*- S3-compatible object storage connection
VITE_ALLOWED_HOSTS- comma-separated host overrides for Vite/dev setupsACTIVATED_PROVIDERS- comma-separated search providersBODY_SIZE_LIMIT- upload/body size limit
If ACTIVATED_PROVIDERS is unset, blank, or contains no valid values, search stays disabled and the search UI remains hidden.
Accepted provider names:
anna,annas,annas-archive, orannasarchiveopenliboropenlibrarygutenbergzliborzlibrary
LIBSQL_URL=libsql://your-database-name.turso.io
LIBSQL_AUTH_TOKEN=your-turso-auth-token
S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
S3_REGION=auto
S3_BUCKET=your-bucket-name
S3_ACCESS_KEY_ID=your-access-key-id
S3_SECRET_ACCESS_KEY=your-secret-access-key
S3_FORCE_PATH_STYLE=false
ACTIVATED_PROVIDERS=anna,openlib,gutenberg
VITE_ALLOWED_HOSTS=
BODY_SIZE_LIMIT=InfinityLIBSQL_URL=file:./sake-selfhosted.db
LIBSQL_AUTH_TOKEN=
S3_ENDPOINT=http://localhost:8333
S3_REGION=us-east-1
S3_BUCKET=sake
S3_ACCESS_KEY_ID=sakeadmin
S3_SECRET_ACCESS_KEY=sakeadminsecret
S3_FORCE_PATH_STYLE=true
ACTIVATED_PROVIDERS=anna,openlib,gutenberg
VITE_ALLOWED_HOSTS=
BODY_SIZE_LIMIT=InfinityIf the database is empty, Sake exposes the normal bootstrap flow in the UI so you can create the first account there. You do not need to predefine a user in the environment.
The KOReader plugin lives in koreaderPlugins/sake.koplugin.
Basic setup flow:
- Install the plugin in KOReader like any other plugin.
- Open
Settings -> More tools -> Sake. - Open
Setup. - Set the public URL of your Sake web app in
Server URL. - Optionally rename the device in
Device Name. - Choose
Pair Deviceand log in with the same username and password you use in the web app. - Use the actions in
Sync,Library Import/Export, andMaintenanceas needed.
The login step exchanges your password for a device API key and clears the password from the device afterward.
You can also export ebooks from the devices home folder back to the web app, including sidecar data such as progress and notes. Great if you have a pre-existing library on your device!
KOReader plugin releases are tracked in the database and the artifacts are served through S3-compatible storage. If the KOReader plugin is updated and you start the app, the new version will be uploaded to S3 so you can use the updater plugin to easily update the core plugin without needing to manually move the files to your KOReader device.
- The Plugin can be found under "Settings" --> "More tools" --> "Sake"
SetupcontainsServer URL,Device Name, andPair Device/Refresh Device KeySynccontainsDownload New Books,Pull Progress From Other Devices, andUpload Current Book Progress- Books are downloaded when pressing
Download New Booksor when setting the device to sleep - Progress is automatically uploaded when putting the device to sleep while a book is still open
- If you use multiple devices, use
Pull Progress From Other Devicesto fetch newer progress from another reader Library Import/Export -> Import or Export Existing Libraryuploads books already on the device, along with sidecar data such as progress and notes- Library import/export can take a while, and the device may be unusable until the process finishes
Maintenance -> Check for Plugin Updateschecks for new plugin releasesMaintenance -> Advanced -> Remote Log Shippingtoggles shipping KOReader logs back to Sake- Before using the plugin you need to set the server URL and pair the device. Your password is removed from the device after pairing succeeds.
- You can optionally change the auto-generated device name. The device name shows up in the web app for device-specific downloads and API keys.
Search is provider-based and routed through POST /api/search.
anna,openlibrary, andgutenbergwork as normal providers once enabled inACTIVATED_PROVIDERSzlibraryalso requires you to connect your Z-Library session inSettings -> Logins
To enable Z-Library support, add it to ACTIVATED_PROVIDERS:
ACTIVATED_PROVIDERS=zlib,anna,openlib,gutenbergIn the app UI, open Settings -> Logins, then use Connect Z-Library and either:
- log in with your email and password, or
- copy
remix_useridandremix_userkeyfrom your Z-Library cookies
The app uses those session values for authenticated Z-Library requests.
Run these from sake/:
bun run dev
bun run build
bun run preview
bun run check
bun run test
bun run db:generate
bun run db:migrate
bun run db:statusFrom the repository root, these compose entry points are available:
docker-compose.yamlfor a managed source builddocker-compose.selfhost.yamlfor a self-hosted source builddocker-examples/docker-compose.prebuilt.yamlfor a managed prebuilt imagedocker-examples/docker-compose.prebuilt.selfhost.yamlfor a self-hosted prebuilt image
This repository is licensed under AGPL-3.0-only.
See LICENSE for the full text.