OpenReader: a self-hosted read-along TTS server for EPUB, PDF, DOCX, TXT and MD
An open-source read-along document reader server with high-quality TTS options, synchronized highlighting, and audiobook export for EPUB, PDF, DOCX, TXT, and MD.
At a glance
- What is it?
- OpenReader is a Next.js document reader that generates speech in the background and highlights words as they are spoken. It is built for people who want their own server, their own storage and their own TTS provider, and it asks for a real deployment in return.
- Who is it for?
- Adopt OpenReader if you already run Docker or a small server and want read-along audio generated by a TTS provider you control, whether that is a local Kokoro-FastAPI instance or a cloud API key. Skip it if you want a zero-setup reading app, or if you only need plain text extraction from PDFs, because the layout model, the storage backend and the auth configuration are all part of the install.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 18, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What OpenReader solves, and who it is actually for
Reading a long document aloud is easy. Keeping the spoken audio aligned with the visible text is not. OpenReader takes a document, splits it into segments, sends those segments to a text-to-speech provider, and stores the resulting audio in one durable timeline that the reader UI can seek through. The highlighting follows the same timeline, so when you jump to a later chapter the cached audio is reused rather than regenerated.
The project supports EPUB, PDF, TXT, MD and DOCX, with DOCX converted by the worker. That format list matters more than it looks. PDF is the hard case, because a PDF has no paragraph structure, only glyphs at coordinates. OpenReader addresses this with PP-DocLayoutV3 running through ONNX for block detection and cross-page stitching, and the README describes geometry-based highlighting as the result. If your library is mostly EPUB and Markdown, most of that machinery sits idle.
The intended user is someone who already runs services. The README points at Docker, Docker Compose, Vercel and a separate compute worker deployment, and the environment example requires an AUTH_SECRET and a BASE_URL before the app will start. This is not a desktop application you double-click.
The generation pipeline: worker, JetStream and a shared cache
OpenReader is a pnpm workspace, not a single Next.js app. The repository lists packages/bootstrap, packages/compute-worker, packages/database, packages/runtime-config and packages/tts, and the build script deploys the bootstrap and compute-worker packages separately. The Next.js frontend is one process; audio generation can be another.
According to the README, the compute worker is coordinated through a NATS JetStream-backed control plane, and word-by-word highlighting comes from ONNX Whisper alignment. Generation is progressive: playback can begin once the first segment exists while the worker keeps producing ahead. Exports are assembled from the same playback cache, which is why a seek, a reload and an audiobook export all cost roughly the same in provider calls.
Storage is a choice rather than a fixed assumption. The environment example enables USE_EMBEDDED_WEED_MINI=true for the default `pnpm start` path, and the README lists embedded SeaweedFS or S3-compatible storage, plus SQLite or Postgres. The Dockerfile pins the embedded SeaweedFS binary to 4.18 specifically because CI observed upload regressions on 4.19, which tells you the embedded path is the one the maintainer exercises most.
Installing OpenReader with Docker and generating a first audiobook
The README sends new users to the Docker Quick Start and the Compose examples, and the repository ships compose files under examples/docker. The package.json exposes the exact commands, so you can start from the repository rather than guessing at flags. The compose script runs the base example:
pnpm composeFor a build from local source, the package.json defines compose:local, which builds the images instead of pulling them:
pnpm compose:localBefore either command will produce a working server, the environment needs auth configured. The .env.example marks BASE_URL and AUTH_SECRET as required, and AUTH_SECRET must stay stable across restarts:
BASE_URL=http://localhost:3003
AUTH_SECRET=replace-with-openssl-rand-base64-32
API_BASE=http://localhost:8880/v1
API_MODEL_NAME=kokoroThe API_BASE default points at port 8880, which is where a local Kokoro-FastAPI instance listens, and the README links a Kokoro-FastAPI guide for running that yourself. One behaviour in the environment file is worth reading twice: on first boot the server seeds these values into a default-openai admin-managed shared provider that is stored in the database and encrypted at rest, and after that the admin UI is authoritative. Changing API_BASE in the environment later has no effect. The comment states the seed path requires auth to be configured.
Once the server is up, the workflow is: sign in, import a document from the library, pick a language and a voice, and start playback. The first segment begins as soon as it is ready. Export to M4B or MP3 is available from the same cache once generation has progressed far enough.
Where OpenReader is the wrong tool
The dependency on a TTS provider is the main boundary. Every provider listed in the README, whether self-hosted OpenAI-compatible servers like Kokoro-FastAPI, KittenTTS-FastAPI and Orpheus-FastAPI or cloud APIs like OpenAI, Replicate and DeepInfra, is something you must supply. There is no bundled offline voice. If you cannot run a local TTS server and do not want to send document text to a cloud API, OpenReader has nothing to read with.
Multilingual support has the same shape. The README states that available languages depend on the configured TTS provider and voice. Choosing a document language does not conjure a voice that the provider does not offer, so a mixed-language library can end up with inconsistent narration.
There is also an operational floor. Auth is required, the database is either SQLite or Postgres, and object storage is either embedded SeaweedFS or S3-compatible. On Vercel, the scheduled-task cron route needs CRON_SECRET, while self-hosted deployments run scheduled tasks in-process and do not. Anyone expecting a single container with no configuration should look elsewhere. And if your goal is simply to extract text from PDFs, the layout model and Whisper alignment are overhead you will pay for and never use.
How OpenReader differs from a plain EPUB reader
A conventional EPUB reader such as Calibre's viewer renders the book and stops there. Audio, if it exists at all, is either a separately produced audiobook or the operating system's screen reader. There is no shared timeline, so there is no word-level highlighting and no export.
OpenReader inverts that. The audio is the primary artifact, generated on demand and cached, and the text view is synchronized to it. That is why the README describes cached audio being reused across seeks, reloads and exports, and why audiobook export in M4B or MP3 is a natural feature rather than an add-on. The cost of this design is that the reader cannot function without a provider, which Calibre never requires.
A closer comparison is a document-to-speech pipeline you assemble yourself from an extractor, a TTS API and ffmpeg. That approach gives you full control and no server to maintain, but you rebuild alignment, caching and highlighting each time. OpenReader's value is that those three pieces already share one timeline.
Licence, maintenance and upgrade cost
OpenReader is MIT licensed, and the LICENSE file sits at the repository root. For self-hosting that is permissive: you can run it, modify it and redistribute it, with the usual requirement to keep the copyright notice. The licence does not extend to the TTS models or provider APIs you connect, and it does not cover the embedded SeaweedFS and nats-server binaries the Dockerfile copies in from their own upstream images, which carry their own terms. Those are separate questions and not ones this article can answer for you.
The last push to the repository was on 2026-09-15, and the most recent tagged release is v4.4.0 from 2026-07-03, following v4.3.0 and v4.2.2 in June 2026. The repository is not archived. The version in package.json matches the v4.4.0 tag.
Upgrade cost is dominated by migrations rather than by the application code. The package.json defines `pnpm migrate`, which runs the database package's migration command, and the README advertises automatic startup migrations. There is also a `migrate-decommission` script that runs a decommission-v4 command from the bootstrap package, which suggests a v4 to v5 transition path exists in the tree, and a v5 directory is present at the repository root. The README does not document rollback, so plan a database backup before running migrations on a library you care about.
Editorial conclusion
Adopt OpenReader if you already run Docker or a small server and want read-along audio generated by a TTS provider you control, whether that is a local Kokoro-FastAPI instance or a cloud API key. Skip it if you want a zero-setup reading app, or if you only need plain text extraction from PDFs, because the layout model, the storage backend and the auth configuration are all part of the install. Before committing, verify three things: that your chosen TTS provider exposes an OpenAI-compatible endpoint at the API_BASE you plan to set, that your host has enough disk for the playback cache, and that the current release notes cover the upgrade path from whatever version you deploy.
Frequently asked questions
What is OpenReader?
OpenReader is an open-source, self-host-friendly text-to-speech document reader built with Next.js. It reads EPUB, PDF, TXT, MD and DOCX with synchronized read-along playback and can export audiobooks in M4B or MP3.
What is the best open source, free PDF reader?
OpenReader is not a general-purpose PDF reader. It parses PDFs with PP-DocLayoutV3 for block detection and geometry-based highlighting, but its purpose is read-along audio, and it requires a configured TTS provider before it can read anything aloud.
What is the reader app?
The README describes OpenReader as an open-source, self-host-friendly text-to-speech document reader for EPUB, PDF, TXT, MD and DOCX, previously named OpenReader-WebUI. It runs as a server rather than as a standalone desktop reader app.
Community notes