Documentation

Installation

Lector is distributed as a Docker image. The recommended way to run it is with Docker Compose.

Docker Compose

Create a docker-compose.yml file:

services:
  lector:
    image: ghcr.io/3stacks/lector:latest
    container_name: lector
    restart: unless-stopped
    ports:
      - "3400:3000"
    volumes:
      - ./data:/app/data
    environment:
      - NODE_ENV=production

Then start it:

docker compose up -d

Lector will be available at http://your-server:3400. All data is stored in a SQLite database inside the data directory.

Updating

# Pull the latest image
docker compose pull

# Restart with the new version
docker compose up -d

Your data is stored in a bind mount and will persist across updates.

Self-hosting

Lector is designed to run on your home network. Your reading history, vocabulary, and learning progress stay on hardware you control. There are no cloud accounts, no telemetry, and no external dependencies beyond optional AI translation.

Network access

Lector is designed to be accessed via a WireGuard VPN. We use Tailscale, which takes about five minutes to set up and gives every device on your tailnet a stable IP. This means your data never leaves your network.

With Tailscale, you can access Lector from your phone, from work, or from anywhere, without exposing any ports to the public internet.

Reverse proxy (HTTPS)

If you want HTTPS within your network (recommended), put Lector behind a reverse proxy. Caddy handles automatic TLS with minimal configuration:

lector.home.yourdomain.com {
    reverse_proxy lector:3000
}

Caddy will automatically provision and renew certificates. Pair this with a local DNS entry (e.g. via Pi-hole or your router) pointing lector.home.yourdomain.com to your server's IP.

Backups

Lector stores everything in a SQLite database and your imported books inside the data directory. To back it up:

# Copy the data directory
cp -r ./data ./backup-$(date +%Y%m%d)

Or include the bind mount path in your regular backup routine (rsync, borg, restic, etc.).

Reading

Lector supports two content formats:

  • EPUB files: upload directly through the library interface
  • Web articles: paste a URL and Lector extracts the content via Readability

You can also paste raw text directly for quick reading practice.

Click-to-translate

Click any word while reading to see its translation. If you have an ANTHROPIC_API_KEY configured, Lector uses Claude for context-aware translation of uncommon words and phrases. Without an API key, it falls back to a built-in dictionary of the top 2000 words.

Coming soon: Local LLM support for translations, so you can run fully offline without any API keys.

Word states

Every word you encounter is tracked with a state:

  • New: you haven't interacted with this word yet
  • Learning: you've looked it up or saved it
  • Known: you've marked it as known

Words are highlighted in your text based on their state, so you can see at a glance how much of a passage you already know.

Cloze Practice

The cloze practice system ships with ~2900 Afrikaans-English sentence pairs from Tatoeba, ordered by word frequency so you learn common words first.

Practice modes

  • Multiple choice: pick the correct word from four options
  • Typing: type the missing word (with optional hard mode that disables hints)

SRS scheduling

Sentences are scheduled using spaced repetition with five mastery levels:

Mastery Interval
0%Immediate
25%1 day
50%3 days
75%7 days
100%14 days

AnkiConnect

Lector connects directly to AnkiConnect running on your local machine. This lets you push vocabulary cards from Lector straight into Anki Desktop. No proxy server, no cloud sync.

Setup

  1. Install the AnkiConnect add-on in Anki Desktop
  2. In AnkiConnect's config, add your Lector origin to the CORS allowlist:
{
  "webCorsOriginList": ["http://localhost:3000"]
}

If you're accessing Lector via a reverse proxy, add that origin too (e.g. https://lector.home.yourdomain.com).

Note: AnkiConnect runs on localhost:8765 by default. The connection is browser-to-localhost, so Anki Desktop must be running on the same machine as your browser.

Configuration

Environment variables

Variable Default Description
NODE_ENV production Set to production for deployed instances
ANTHROPIC_API_KEY Optional. Claude API key for AI-powered word and phrase translation. Without it, Lector falls back to a local dictionary of the top 2000 words.
GOOGLE_CLOUD_API_KEY Optional. Google Cloud API key for text-to-speech pronunciation.

Full Docker Compose example

Here's a complete example with all optional environment variables:

services:
  lector:
    image: ghcr.io/3stacks/lector:${LECTOR_VERSION:-latest}
    container_name: lector
    restart: unless-stopped
    ports:
      - "3400:3000"
    volumes:
      - ./data:/app/data
    environment:
      - NODE_ENV=production
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
      - GOOGLE_CLOUD_API_KEY=${GOOGLE_CLOUD_API_KEY}

Supported languages

Lector's reader works with any language, but language packs provide sentence banks and dictionaries for cloze practice.

Language pair Status Sentences
Afrikaans → English Available ~2900
Spanish → English Coming soon
German → English Coming soon

All sentence data is sourced from Tatoeba. Adding a new language pair is straightforward. If you'd like to see your language supported, open a PR on GitHub. We'd love contributions.

Sentence bank

The cloze practice system ships with ~2900 Afrikaans-English sentence pairs sourced from Tatoeba. Each sentence is tagged with word frequency data so you learn the most common words first.

To regenerate from Tatoeba's latest data dumps:

npm run fetch-sentences

This downloads Tatoeba's per-language TSV exports, joins Afrikaans sentences with English translations, and tags each with word frequency data.

Data attribution: Sentence bank sourced from Tatoeba, licensed under CC-BY 2.0 FR. Word frequency dictionary compiled from publicly available frequency lists.

Tech stack

  • Framework: Next.js 16 with React 19
  • Database: SQLite (better-sqlite3) server-side, Dexie (IndexedDB) client-side
  • Styling: Tailwind CSS v4
  • AI: Anthropic Claude API (optional)
  • TTS: Google Cloud Text-to-Speech (optional)
  • Container: Docker (single image, bind mount for data)