Skip to main content
This guide builds a search API over public-domain books with LanceDB, an embedded vector database that stores tables as files, so there’s no database server to run. An indexer in a persistent sandbox writes the table to an Archil disk. Search replicas mount the same disk read-only and answer vector, filtered, and hybrid (vector plus full-text) queries over HTTPS. When you add or delete documents, the indexer updates the table in place and every replica serves the new version without a restart. Embeddings come from all-MiniLM-L6-v2, a small open model that runs on CPU, so no model-provider API key is needed.

Prerequisites

Export your Archil API key and a region that offers sandboxes (aws-us-east-1, aws-us-west-2, or aws-eu-west-1), and install the SDK for the language you orchestrate from. You’ll also need curl and jq.
The indexer sandbox downloads books from Project Gutenberg and the embedding model from Hugging Face. Sandboxes on the Developer plan can reach only a managed allowlist that doesn’t include those hosts, so this guide needs the Team plan or above.

Write the ingest job

This script runs inside the indexer sandbox. add downloads books from Project Gutenberg, splits them into paragraphs, embeds each one, and writes them to the books table. The first add creates the table with a vector index and a full-text index; later ones append rows and call optimize(), which folds the new rows into both indexes without rebuilding them. delete removes a book’s rows.
ingest.py

Run the indexer

This script creates the disk and a long-lived indexer sandbox the first time, reuses them after that, and runs ingest.py with whatever arguments you pass. The indexer mounts the disk in conditional mode, which sends writes straight to the server and takes no lock, so search replicas can stay attached read-only while it writes.
Load five books: Sherlock Holmes, Pride and Prejudice, Frankenstein, Moby Dick, and Alice in Wonderland. The first run takes about a minute, most of it embedding.

Write the search server

Each replica runs this server. GET /search?q=... runs a vector search; add book=... to filter by title, or mode=hybrid to combine vector and full-text ranking. A background thread follows the table as the indexer commits. LanceDB records the latest version in latest_version_hint.json; every second the server re-reads just that file from the server with archil invalidate-cache, and when it moves, refreshes the mount’s cached lookups and checks out the new version. Requests keep running against the old version until the switch.
search_server.py

Deploy a search replica

This script creates a sandbox that mounts the disk with readOnly, runs the server as a supervised service (restarted on failure and after reboots), and waits until it answers. The port stays private: the script creates a port token, which callers send in the X-Archil-Token header, and appends the replica’s URL and token to replicas.txt.
Deploy the first replica and query it from your machine. The second query narrows the search to one book, and the third ranks by both meaning and the literal words:
The vector index is approximate, so your exact results can differ slightly. Without the X-Archil-Token header, the same request gets a 401.

Scale out

Read-only mounts take no lock, so any number of replicas can attach to the disk alongside the indexer. Add a second replica, then send a query to both:

Add and delete documents

Dracula isn’t in the table yet, so that query has no good answer. Add it while both replicas keep serving. Only the new paragraphs are embedded and indexed:
Run the same loop again, and both replicas answer from the new version:
Deleting works the same way. Remove Alice in Wonderland, give the replicas a moment to pick up the new version, then search each one with a filter on that book:
To change rows in place, use table.update(), or table.merge_insert() for upserts keyed on a column. Each commit is a new table version, which the replicas pick up the same way.

Clean up

Stop and delete every sandbox that mounts the disk, then delete the disk.

Next steps