A lightweight, self-hosted PDF & EPUB library with a blazing-fast full-text search engine and a beautiful built-in web reader.
Important
NextChapter began as an enhanced fork of Inkheart by Nystik and has grown into its own project β adding native EPUB reading, multi-arch CI/CD (linux/amd64 + linux/arm64), nine curated themes, and a deeply reworked reader experience.
Your filesystem is the source of truth. No database. No metadata curation. No lock-in.
Drop your files into folders, point NextChapter at the directory, and it:
- π Mirrors your exact folder hierarchy
- πΌοΈ Extracts high-resolution cover art automatically
- π Builds an instant full-text search index (PDF pages and EPUB chapters)
- π Serves it all through a sleek web reader β desktop, tablet, and mobile
It deliberately does one thing exceptionally well: a fast, beautiful way to read and search your own documents. It's not a comic scraper, not an OPDS manager, not a metadata librarian.
| π Library | π Readers |
|---|---|
|
|
| π¨ Appearance | π‘οΈ Operations |
|
|
Create a docker-compose.yml:
services:
nextchapter:
image: ghcr.io/keshavsapra/nextchapter:latest
container_name: nextchapter
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- /path/to/your/books:/media # Your PDFs and EPUBs
- /path/to/covers:/covers # Extracted cover images
- /path/to/thumbnails:/thumbnails # OpenGraph preview thumbnails
- /path/to/config:/config # Search index, settings, and pins
environment:
- BIND_ADDR=0.0.0.0
- BIND_PORT=8080
- SCAN_INTERVAL=600 # Filesystem re-scan interval in seconds
- TEXT_INDEX_ENABLED=true # Enable full-text search indexingEnsure the storage directories exist with write permissions for the container's non-root user (UID 1000):
mkdir -p /path/to/{covers,thumbnails,config,books}
sudo chown -R 1000:1000 /path/to/covers /path/to/thumbnails /path/to/configTip
Alternatively, set user: "0:0" in the compose file to run as root on the host.
Then:
docker compose up -dβ¦and open http://localhost:8080.
Note
The first index build over a large collection can take a few minutes. Since /config is persisted, later restarts only scan for new or modified files.
Images are published as multi-architecture containers (linux/amd64, linux/arm64) β Docker picks the right one automatically:
| Platform | Works with |
|---|---|
| Linux / VPS | Ubuntu, Debian, Fedora, Arch, Alpine |
| Home servers / NAS | Synology, Unraid, TrueNAS SCALE, QNAP, Portainer |
| Single-board | Raspberry Pi 4B / 5, Rock Pi, Orange Pi |
| macOS / Windows | Docker Desktop, including native Apple Silicon |
docker run -d \
--name nextchapter \
--restart unless-stopped \
-p 8080:8080 \
-v /path/to/your/books:/media \
-v /path/to/covers:/covers \
-v /path/to/thumbnails:/thumbnails \
-v /path/to/config:/config \
ghcr.io/keshavsapra/nextchapter:latestConfigure via environment variables or a nextchapter.toml (legacy inkheart.toml also accepted).
| Environment Variable | Description | Default |
|---|---|---|
MEDIA_DIR |
Directory containing your PDF and EPUB files | /media |
IMAGE_DIR |
Directory where book covers are cached | /covers |
THUMBNAIL_DIR |
Directory for on-demand page preview thumbnails | /thumbnails |
CONFIG_DIR |
Directory storing user data, pins, collections, and search index | Parent dir of CONFIG_PATH |
CONFIG_PATH |
Optional path to a nextchapter.toml file |
./nextchapter.toml |
BIND_ADDR |
Network address the server binds to | 127.0.0.1 (0.0.0.0 in Docker) |
BIND_PORT |
HTTP port | 8080 |
SCAN_INTERVAL |
Filesystem scan interval for changes (in seconds) | 600 (10 min) |
COVER_WIDTH |
Width in pixels for extracted cover art | 900 |
THUMBNAIL_WIDTH |
Width in pixels for preview thumbnails | 300 |
TEXT_INDEX_ENABLED |
Enables full-text search indexing | true |
BASE_PATH |
Subdirectory path prefix (e.g. /books) when behind reverse proxy |
"" |
FIREBASE_CONFIG_PATH |
Path to firebase.json for optional Google/email auth |
./firebase.json |
FIREBASE_WHITELIST |
Path to text file with whitelisted user IDs | None |
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Set BASE_PATH=/library in the container environment, then:
location /library/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Works the same with Caddy, Traefik, or Cloudflare Tunnels.
docker build -t nextchapter:local -f docker/dockerfile .Every push triggers .github/workflows/docker.yml, which builds multi-arch images (linux/amd64, linux/arm64) and publishes them to GitHub Container Registry (ghcr.io).
nextchapter/
βββ backend/ # Rust Actix-Web server
β βββ indexer/ # Filesystem scanner, PDF/EPUB cover & chapter extraction
β β βββ text_search/# Tantivy search engine, mtime change tracking, HTML parser
β βββ server/ # REST API routes, auth extractor, static file serving
β βββ pdfium/ # Native PDFium bindings for PDF rendering
βββ frontend/ # Svelte 4 SPA
β βββ src/ui/ # NativePdf (PDF.js) & EpubReader (epub.js) components
β βββ src/stores/ # LocalStorage reading progress, themes, collections, pins
βββ docker/ # Multi-stage multi-arch Dockerfile (cargo-chef + node + distroless)
- Inkheart was originally created by Nystik (original repo Β· support Nystik on Ko-fi)
- EPUB support, multi-architecture CI/CD, and all further enhancements by Keshav Sapra
- Licensed under the Apache License, Version 2.0 β free to use, modify, and distribute under its terms
- Logo and branding assets are copyright of their respective authors
Built with π¦ Rust, β‘ Svelte, and π far too many unread books





