Self-hosted service
pacexy/flow avatar
pacexy/flow

pacexy/flow: a browser-based ePub reader you can self-host

Browser-based ePub reader

3,336 stars292 forksTypeScriptAGPL-3.0

At a glance

What is it?
Flow is an AGPL-3.0 ePub reader built on Next.js, React, TypeScript and Epub.js, distributed as a pnpm monorepo and a Docker image. It is aimed at readers who want annotations, themes and cloud storage in a browser tab rather than a native app.
Who is it for?
Adopt Flow if you want an ePub reader you can run yourself, on your own hardware, with an AGPL-3.0 licence you can live with. Skip it if you need a native Android or iOS app, or if you want a drop-in binary with no environment configuration.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 180 days ago.
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 23, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What pacexy/flow actually is and who it is for

Flow is an ePub reader that runs in a browser. The README's own summary is short: "Free. Open source. Browser-based." The repository is a pnpm monorepo with an apps/ directory and a packages/ directory, a Turborepo task runner, and a Next.js app under apps/reader. The website lives in apps/website. The primary language is TypeScript.

The feature list covers grid layout, search in book, image preview, custom typography, highlight and annotation, themes, share or download a book with a link, data export, and cloud storage. That combination puts it in a different category from a minimal ePub viewer: the annotation and export features imply you are meant to keep a library, not just open one file. Cloud storage is listed as a feature, which is why environment variables exist at all.

Who it is for: someone who reads DRM-free ePub files, wants their highlights to survive a browser change, and is willing to run a Node process or a container. Who it is not for: anyone who expects to install it from an app store. The topics list includes pwa, so the browser tab can behave like an installed app, but the repository contains no Android or iOS project. The related searches that ask about "Pacexy flow android" have no matching artifact here.

How the monorepo is put together

The root package.json is named @flow/monorepo and is marked private. Its scripts delegate to Turbo: build runs turbo run build, dev runs turbo run dev --parallel, lint runs turbo run lint. The packageManager field pins pnpm@10.6.4 with an integrity hash, and engines requires node >=18.0.0. Turbo itself is pinned at 1.11.3 in devDependencies, alongside TypeScript 4.6.3, ESLint 8.13.0 and eslint-config-next 12.1.5.

That version set is worth reading carefully. TypeScript 4.6 and Next.js 12 era lint config are older than what a new project would start with in 2026, and the last push to the repository was on 2026-03-28. The repository is not archived, but it is not moving quickly either. A contributor should expect to work within those pinned versions rather than upgrade them casually, because turbo prune in the Dockerfile depends on the workspace layout staying stable.

The rendering layer is Epub.js, credited in the README alongside React, Next.js, TypeScript, Vercel and Turborepo. The README credits list is the only place the ePub engine is named; it does not describe how Flow wraps it, so the integration details have to be read from apps/reader source rather than documentation.

Installing Flow from source with pnpm

The README lists Node.js, pnpm and Git as prerequisites. Clone the repository first, then install dependencies from the workspace root. Because this is a pnpm workspace, running npm install instead would not respect pnpm-workspace.yaml and pnpm-lock.yaml.

bash
git clone https://github.com/pacexy/flow
cd flow
pnpm i

The README then says to copy and rename all .env.local.example files to .env.local and set up the environment variables. Note the plural: there is more than one example file, and the README does not enumerate the keys inside them. This is the least documented step in the whole setup, and it is the one most likely to block a first run, particularly if cloud storage is enabled.

bash
pnpm dev

pnpm dev runs turbo run dev --parallel, so the reader and website apps start together. To build for production instead, the root script is pnpm build, which runs turbo run build. The README does not document which port the dev server binds to; the Docker path below fixes port 3000 explicitly.

Self-hosting with Docker Compose

For a server deployment, the README points at docker-compose. The compose file defines a single service named reader, container_name reader, restart always, mapping host port 3000 to container port 3000, and loading ./apps/reader/.env.local as the env file. That env_file line is the reason the README says to set up environment variables before self-hosting: without that file, the container starts without whatever configuration the reader expects.

bash
docker compose up -d

The manual route builds the image and passes the same env file at runtime:

bash
docker build -t flow .
docker run -p 3000:3000 --env-file apps/reader/.env.local flow

The Dockerfile is a three-stage build. The builder stage runs turbo prune --scope=@flow/reader --docker to isolate only the packages the reader needs. The installer stage enables corepack and runs pnpm i --frozen-lockfile, then builds with DOCKER=1 pnpm -F reader build. The runner stage copies the Next.js standalone output and starts it with node apps/reader/server.js as a non-root nextjs user. The DOCKER=1 variable is set inside the image build; it is not something you pass at runtime.

Where Flow is the wrong tool

The most concrete limitation is the platform gap. There is no Android or iOS application in the repository, and the README does not claim one. If your reading happens on a phone away from a browser, Flow does not address that, and the PWA topic is not a substitute for a native client with offline file handling.

Second, the configuration surface is under-documented. The README tells you to copy .env.local.example files and set environment variables but never lists the variables, their defaults, or what happens when cloud storage is unconfigured. A self-hoster has to open the example files in the repository to learn what is required. That is a documentation gap, not a bug, but it changes the effort estimate for deployment.

Third, the licence. Flow is AGPL-3.0. If you modify it and expose it to users over a network, the AGPL's network clause is relevant to how you distribute those modifications. That is a real constraint for anyone planning to run a customized instance as a service, and it is stricter than MIT or Apache-2.0. This is not legal advice; read the LICENSE file and, if it matters commercially, get proper counsel.

Finally, the pinned toolchain is old. TypeScript 4.6.3 and eslint-config-next 12.1.5 in the root devDependencies mean a contributor bringing current tooling will spend time reconciling versions rather than writing features.

How Flow differs from Epub.js examples and from a desktop reader

The related searches surface "Epubjs examples," and the distinction matters. Epub.js is a library: it gives you rendering primitives and you assemble the reader. Flow is an application built on top of it, with a library, annotations, themes, search, export and optional cloud storage already wired together. If you want to embed ePub rendering inside your own product, Epub.js is the lower-level choice and Flow would be the wrong dependency to reach for. If you want a reader that already has a highlight system and a grid library view, building that on raw Epub.js is the work Flow has already done.

The comparison against a desktop reader such as Calibre's viewer or a native app is a different axis. Those run locally with full filesystem access and no server. Flow's cloud storage and share-by-link features assume a server you control, which is the trade: you get access from any browser and a link you can send, and in exchange you run and maintain a Node process. Anyone who wants zero infrastructure should not pick this.

Maintenance, upgrade cost and licence

The last push to the default branch was on 2026-03-28. The repository is not archived. There are no releases retrieved for this project, so there is no tagged version to pin against; deployment means tracking the main branch or a commit of your choosing. That is a real operational fact: with no release artifacts, you cannot say "we run Flow 1.2" and hold it there while reading a changelog.

Upgrading means pulling the branch and re-running pnpm i against the committed pnpm-lock.yaml, then rebuilding. The Docker path rebuilds from source each time, so a redeploy is a full turbo prune and Next.js build, not an image pull. For a small self-hosted instance that is acceptable; for anything with a maintenance window it is worth knowing before you start.

On licence: AGPL-3.0 is a copyleft licence with a network-use provision. Running an unmodified copy for yourself is straightforward. Modifying it and letting other people use it over a network is where the obligations attach. The repository ships a LICENSE file at the root; that file, not this article, is the authority.

Editorial conclusion

Adopt Flow if you want an ePub reader you can run yourself, on your own hardware, with an AGPL-3.0 licence you can live with. Skip it if you need a native Android or iOS app, or if you want a drop-in binary with no environment configuration. Before committing, verify what the .env.local.example files require for cloud storage, since the README points at them without listing the keys, and check the Docker build path with turbo prune --scope=@flow/reader against your own Node 18 environment.

Frequently asked questions

Is pacexy/flow free to use?

Yes. The README describes it as free and open source, and the repository is licensed AGPL-3.0. The AGPL's network clause means modified versions exposed to users over a network carry source-distribution obligations.

Does pacexy/flow have an Android or iOS app?

The repository contains no Android or iOS project, and the README does not describe a native mobile app. Flow runs in the browser, and the repository topics list pwa, so it can be installed as a browser app rather than shipped through an app store.

How do I self-host pacexy/flow with Docker?

Set up the environment variables first by copying the .env.local.example files to .env.local, then run docker compose up -d. The compose file maps port 3000 and loads ./apps/reader/.env.local. Alternatively, build with docker build -t flow . and run with --env-file apps/reader/.env.local.

What are the prerequisites for running pacexy/flow from source?

The README lists Node.js, pnpm and Git. The root package.json requires node >=18.0.0 and pins pnpm@10.6.4 as the package manager, so install dependencies with pnpm i rather than npm.

Official sources

  1. Issues
  2. License: AGPL-3.0
  3. pacexy/flow on GitHub
  4. Project website
  5. README
Community notes

Community notes