Skip to content

The Web App (indx app)

indx app launches a local web UI that exercises every indx feature end-to-end from the browser: pick and edit each component slot, run a build and watch the pipeline stream live, then inspect and query the produced knowledge space. It is the visual counterpart to the CLI and the SDK — the same pipeline and data model, driven entirely from configuration.

The app is an opt-in extra. The core install stays light, and import indx never pulls the web stack.

The web app ships as the optional app extra:

Terminal window
pip install "indx[app]"

This adds FastAPI and uvicorn. Without the extra, indx app fails loud with an install hint and exits 1 (it is a plain IndxError, not a configuration error). See errors and exit codes.

Terminal window
indx app # http://127.0.0.1:8000, opens a browser
indx app --no-open --port 9000 # bind a different port, don't open a browser

The command starts a local FastAPI server and (unless --no-open is passed) opens the UI in your browser. It runs on a single origin — the same server serves both the UI and the /api endpoints — so there is no CORS to configure. The app operates on server-side paths: it reads directories and writes archives on the machine running indx app, which is your own machine.

FlagTypeDefaultDescription
--hoststr127.0.0.1Interface to bind.
--portint8000Port to serve on.
--open / --no-openflag--openOpen (or don’t open) a browser on start.
--config, -cpath./indx.toml if presentConfiguration file to load into the editor.

The UI is organized into four tabs that follow the natural workflow — configure, build, inspect, query.

  1. Config — a dropdown per slot (parser / llm / vlm / embedder / store / output), populated live from the registry. Backends that need an uninstalled extra are badged so you can see what a stack would require. Edit backend-specific sub-tables, validate the config as you type, and save an indx.toml to the server’s working directory.
  2. Build — pick a directory (or a .zip) and an output path, set flags (offline / no-embed / dry-run / resume / jobs), then run. The pipeline stages stream live — walk, parse, chunk, relate, enrich, embed-pack — ending in a summary card with document/chunk/relation counts and per-stage timings. A Run demo button builds the bundled demo corpus offline so you can try inspect and query immediately. A dry run walks the directory and shows the plan (files, folders, selected components) without running any models.
  3. Inspect — open a produced space (a .indx archive or a jsonl output directory) and see its stats, the document-type histogram, relation-type counts, and a document table (path, type, topics, tags, chunk count). This is the visual form of indx inspect.
  4. Query — run a semantic search against the space and read the ranked SearchHits: score, source path, chunk text, and the resolved neighbor chunks. Filter by document type. This mirrors indx query.

By default the editor reflects the documented cloud defaults (docling / openai:gpt-5-mini / openai:text-embedding-3-small / qdrant), which need extras and API keys. The Config and Build tabs expose an Offline preset toggle that fills any unset slot with the zero-dependency core stack — exactly like the CLI --offline flag:

SlotOffline preset
Parserplaintext
LLMnone
VLMnone
Embedderhash
Storejsonl
Output.indx

The preset is an explicit toggle, not a change to your product defaults — the cloud stack remains the default everywhere else. It is the fastest way to get a complete build running with zero installs and no network. See Local & air-gapped for the offline stack in depth.

The UI is a Next.js app exported to static HTML/CSS/JS (output: 'export'). That export is bundled into the wheel and served by FastAPI from inside the package — so at runtime there is no Node process. Node is a build-time dependency only: it produces the static bundle, which is then packaged and served as plain files.

In production (indx app), FastAPI serves the exported UI at / and the API under /api. Any non-/api path returns the app’s index.html, so client-side routing works as a single-page app.

For UI development you run the two halves separately, with hot reload on the frontend:

Terminal window
# terminal 1 — backend (the app extra)
pip install fastapi "uvicorn[standard]"
indx app --no-open # FastAPI on :8000 (the static bundle may be absent in dev)
# terminal 2 — frontend (hot reload, proxies /api → :8000)
cd webapp && npm install && npm run dev # Next on :3000

In dev, Next runs on :3000 and proxies /api/* to the FastAPI server on :8000, so you edit the UI with live reload while the real backend serves data. To produce the shippable bundle that indx app serves:

Terminal window
bash scripts/build_webapp.sh # next build → src/indx/app/static/

Every UI action is a call to a small JSON + SSE API under /api: health, components, config (read / validate / write), build (a Server-Sent Events stream of stage events), dry-run, inspect, query, demo, and browse (a server-side directory picker). The build stream emits a start event, a stage event per pipeline stage, and a terminal done event carrying the BuildSummary; a dry run emits a single terminal plan event instead.

The endpoints serialize the real core models as-is — SpaceStats, SearchHit (.chunk, .score, .neighbors; the matched chunk carries its provenance at hit.chunk.source), Document — so the shapes match the data models reference and the CLI --json output. The full request/response contract, including the SSE event schema, lives in the internal spec, docs/app-spec.md.