# Readest Architecture
This document gives a system-level view of Readest: how the pieces fit together,
which side of the wire each piece runs on, and what each module is responsible
for. It complements [`code-layout.md`](./code-layout.md), which focuses on the
directory layout. Read this one first if you want to understand the system; read
that one when you need to find a specific file.
The diagrams use [Mermaid](https://mermaid.js.org/) and render natively on
GitHub.
## 1. High-level picture
Readest is a single TypeScript/React codebase (`apps/readest-app`) compiled into
multiple targets:
- a **desktop app** (Windows / macOS / Linux) via Tauri v2
- a **mobile app** (Android / iOS) via Tauri v2 mobile
- a **web app** running on Next.js / Cloudflare Workers (OpenNext) at
[web.readest.com](https://web.readest.com)
- two **side surfaces**: a "Send to Readest" browser extension
(`apps/readest-app/extension/send-to-readest`) and a Windows thumbnail
shell extension (`apps/readest-app/extensions/windows-thumbnail`)
The same React UI runs in all targets. What differs is the **host shell** under
the UI and the **set of services** that the UI binds to at runtime — see
section 4.
```mermaid
flowchart LR
subgraph Clients
Desktop["Desktop app
(Tauri shell + React UI)"]
Mobile["Mobile app
(Tauri Android/iOS + React UI)"]
Web["Web app
(Next.js + React UI)"]
Ext["Browser extension
(Send to Readest)"]
WinExt["Windows shell ext
(thumbnail provider)"]
end
subgraph Backend["Readest backend (Next.js routes + Cloudflare Worker)"]
AppApi["src/app/api/*
(App Router)"]
PagesApi["src/pages/api/*
(Pages Router)"]
RuntimeCfg["/runtime-config.js
(server-injected config)"]
Worker["workers/send-email
(Cloudflare Worker)"]
end
subgraph Cloud["External services"]
Supabase["Supabase
(auth + Postgres)"]
S3["Object storage
(S3 / R2)"]
Stripe["Stripe
(billing)"]
AI["AI providers
(OpenAI / Ollama / ...)"]
Trans["Translators
(DeepL / Google / Azure / Yandex)"]
Meta["Metadata providers
(Google Books / Open Library)"]
Dict["Dictionary sources
(Wikipedia / Wiktionary / StarDict)"]
OPDS["OPDS catalogs / Calibre"]
Hardcover["Hardcover GraphQL"]
Readwise["Readwise"]
TTS["Edge TTS"]
IAP["Apple / Google IAP"]
end
Desktop --> Backend
Mobile --> Backend
Web --> Backend
Ext --> PagesApi
WinExt -.reads files.-> Desktop
PagesApi --> Supabase
PagesApi --> S3
PagesApi --> Trans
AppApi --> Supabase
AppApi --> Stripe
AppApi --> AI
AppApi --> Meta
AppApi --> OPDS
AppApi --> Hardcover
AppApi --> TTS
AppApi --> IAP
Web -.direct.-> Dict
Desktop -.direct.-> Dict
Mobile -.direct.-> Dict
Web -.direct.-> Readwise
Desktop -.direct.-> Readwise
```
The `Backend` box is **the same code on all clients**. In the web target it is
deployed as a Cloudflare Worker (via `@opennextjs/cloudflare` and
`wrangler.toml`). In the Tauri targets the same routes are served by a Next.js
runtime, but most clients hit the production deployment over HTTPS.
## 2. Process boundaries
There are three runtimes in play:
```mermaid
flowchart TB
subgraph Browser["Web runtime (browser / Tauri webview)"]
UI["React UI
(src/app, src/components, src/hooks, src/store)"]
Domain["Shared domain layer
(src/services, src/utils, src/libs)"]
Foliate["foliate-js
(packages/foliate-js)"]
SW["Service worker (sw.ts)"]
TursoWasm["Turso WASM
(replica DB in browser)"]
end
subgraph Native["Tauri native host (Rust)"]
TauriCore["src-tauri/src/lib.rs
(commands, dir_scanner, transfer_file, clip_url, discord_rpc)"]
Plugins["Tauri plugins
(fs, dialog, http, oauth, deep-link, opener, updater,
native-bridge, native-tts, turso, webview-upgrade)"]
end
subgraph Server["Next.js server (Worker / Node)"]
Routes["App Router + Pages Router routes"]
Mw["middleware.ts
(CORS + COOP/COEP)"]
RuntimeRoute["app/runtime-config.js
(server-rendered config script)"]
end
UI --> Domain
Domain --> Foliate
UI --> SW
Domain --> TursoWasm
Domain -- "@tauri-apps/api invoke()" --> TauriCore
TauriCore --> Plugins
Domain -- "fetch(/api/...)" --> Routes
Browser -- "