Contributing to Reader
May 13, 2026 · View on GitHub
Thanks for your interest in contributing. This is the open source branch of the codebase that runs at https://r.jina.ai and https://s.jina.ai. The MongoDB-backed SaaS storage layer is not part of this branch — local development uses the stateless / bucket-cached modes only.
If you're not sure where to start, take a look at architecture.md first.
Local development
Requirements
- Node.js 22+ — earlier versions will not build.
- Docker (optional) — only needed if you want to run the bucket-cached storage mode against a local MinIO. Pure stateless mode needs nothing extra.
- LibreOffice (optional) — only needed if you want to test MS Office document handling locally.
First-time setup
git clone git@github.com:jina-ai/reader.git
cd reader
npm install
# Optional: only if you want the local bucket cache
docker compose up -d
docker compose up -d starts:
| Service | Port(s) | Purpose |
|---|---|---|
minio | 9000, 9001 | S3-compatible object storage for cached pages. Console on :9001. |
Running the server
In VSCode, press F5 to launch the debugger.
Or, after exporting the environment variables (see below):
docker compose up -d
npm run dev
Useful scripts
npm run build— TypeScript compile (also runs an integrity check).npm run build:watch— incremental build.npm run start— run the compiledcrawlentrypoint.npm run dry-run— runsearch.jswithNODE_ENV=dry-runto resolve the DI graph and exit. Used to warmNODE_COMPILE_CACHEin the Dockerfile.npm run lint— ESLint over.js/.ts.
Environment variables
Reader picks up configuration from environment variables. The most relevant ones for local development are:
Storage & data
| Variable | Notes |
|---|---|
GCP_STORAGE_ENDPOINT | Object storage endpoint (use the local MinIO endpoint for dev). Enables Stage 1 bucket-cached mode. |
GCP_STORAGE_BUCKET | Bucket name for cached objects. |
GCP_STORAGE_ACCESS_KEY | MinIO root user locally. |
GCP_STORAGE_SECRET_KEY | MinIO root password locally. |
GCP_STORAGE_REGION | Optional; for parity with GCS. |
GCLOUD_PROJECT | Alternative trigger for the bucket layer when combined with GCP_STORAGE_ENDPOINT. |
CACHE_LOCAL_STORAGE_ROOT | Filesystem root for local cache (alternative to object storage in stateless modes). |
Vendors & integrations
| Variable | Purpose |
|---|---|
JINA_SERP_API_KEY / JINA_SERP_API_ORIGIN | Jina SERP backend. |
JINA_SERP_API_POLICY | SERP routing policy. |
SERPER_SEARCH_API_KEY | serper.dev search backend. |
THORDATA_PROXY_URL / THORDATA_PROXY_URL_ALT | Thordata residential proxy. |
THORDATA_SERP_API_KEY | Thordata SERP API. |
BRIGHTDATA_PROXY_URL / BRIGHTDATA_ISP_PROXY_URL / BRIGHTDATA_SERP_API_KEY | BrightData proxy + SERP. |
CLOUD_FLARE_API_KEY | Required for the cf-browser-rendering engine. |
STRIPE_SECRET_KEY / STRIPE_WEBHOOK_KEY | Billing integration. |
OPENAI_API_KEY / ANTHROPIC_API_KEY / OPENROUTER_API_KEY / GOOGLE_AI_STUDIO_API_KEY / REPLICATE_API_KEY | LLM/VLM access. |
Overrides & toggles
| Variable | Purpose |
|---|---|
PORT | HTTP port. |
NODE_ENV | dry-run is recognized for offline search runs. |
DEBUG_BROWSER | Run headless Chrome with non-headless / debug behavior. |
OVERRIDE_CHROME_EXECUTABLE_PATH | Use a specific Chrome binary instead of the bundled Puppeteer one. |
OVERRIDE_JINA_VLM_URL | Point at a different VLM endpoint. |
OVERRIDE_READERLM_V | Switch between ReaderLM versions. |
OVERRIDE_GOOGLE_DOMAIN / OVERRIDE_BING_DOMAIN | Use a regional search domain. |
OVERRIDE_MANAGE_SERVER_URL | Redirect calls to the management server. |
JINA_BOGO_SITES_RESORT_ORIGIN | Origin for the bogo-sites resort list. |
JINA_CRAWLER_OFFLOAD_ORIGIN | Offload crawler traffic to a peer cluster. |
PREFERRED_PROXY_COUNTRY | Hint for proxy country selection. |
SLACK_REPORT_WEBHOOK_URL | Slack channel for runtime reports. |
SECRETS_COMBINED
You can pass a base64-encoded JSON object via SECRETS_COMBINED to bundle multiple variables into one. See src/services/envconfig.ts.
Tests
The repo uses the Node.js built-in test runner (no Jest, no Vitest).
npm run test:unit # unit tests
npm run test:e2e # end-to-end tests (slower, hits docker services)
npm test # both
npm run test:unit:coverage
npm run test:e2e:coverage
npm run test:coverage # combined coverage report (c8)
Tests are written in TypeScript under tests/ and compiled into tests-build/ before running. The test entrypoints are tests-build/run-unit.js and tests-build/run.js.
Submitting changes
- Open an issue first if the change is non-trivial — it saves churn for both sides.
- Keep PRs focused. A bug fix and a refactor in the same PR are harder to review and revert.
- Run
npm run lintandnpm testbefore pushing. - Reference the issue in the PR description if one exists.
Reporting issues
Bug reports are most useful when they include:
- The exact URL (for
r.jina.ai) or query (fors.jina.ai). - The request headers in use, especially any
x-*overrides. - The expected vs actual output.
Open an issue on GitHub and we'll take a look.