Getting started with PersiaDB
Getting started with PersiaDB means separating this Rust search library’s design from the code you can call.
The design is embedded full-text search in Rust: a library in your process, one file, ranked results, and no search daemon.
Persia DB is pre-alpha. The public persia crate has no Db::open. persia-engine can put, delete, and commit a document. persia-engine runs a ranked search over a collection snapshot: BM25F, filters, sorts, facets, and pages.
The first release a caller is supposed to use is v0.1 (M10). That milestone is blocked on M6 (in progress), M7 (in progress), M8 (not started), and M9 (not started).
What you can call today is library code. persia-engine creates a database file, writes documents, and searches a collection snapshot; the README quickstart runs those calls. That is not persia::Db::open.
What is an embedded search database? defines that in-process shape. The comparison places the design next to SQLite FTS5, Tantivy, and Meilisearch, and it is not a benchmark. The FAQ has the short answers. When this page and the SPEC disagree, the SPEC wins. Live status is PROGRESS.md: 321 of 521 roadmap leaves done (62%) in the 2026-11-05 PROGRESS.md snapshot, with 0 marked in progress. The same snapshot, by milestone, is the roadmap.
What this Rust search library implements today
Section titled “What this Rust search library implements today”The crates are not published (publish = false in the workspace). There is no crates.io release and no cargo add persia.
persia, the embedded API crate, exports no types. Its source is the module docs in lib.rs. There is no Db and no Collection.
persia-server is a placeholder binary: it prints “not implemented (M11)” and exits with status 1. No gRPC or HTTP server runs.
persia-cli lists and removes temporary and quarantine files next to a container or a local store (persia container files, persia container sweep, persia store files, persia store sweep). It can inspect and dump one segment file (persia inspect segment, persia dump segment, with --verify on inspect), and check a whole database read-only (persia verify). It does not compact, import, or search.
persia-format encodes and decodes on-disk bytes. It does not open a file as a database. A git dependency, for code that wants those codecs:
[dependencies]persia-format = { git = "https://github.com/tomiok/persiaDB" }This round-trips a container header (SPEC §4.2). It is the doctest on Header. It does not create app.persia and it does not search:
use persia_format::header::{Access, HEADER_LEN, Header};use persia_format::{Reader, Writer};
let header = Header::new([7; 16]);let mut w = Writer::new();header.encode(&mut w)?;assert_eq!(w.len(), HEADER_LEN);
let decoded = Header::decode(&mut Reader::new(w.as_slice()))?;assert_eq!(decoded, header);assert_eq!(decoded.access(), Access::ReadWrite);Also implemented in that crate, and only as byte codecs: checksums, integer blocks, zstd block compression, block framing, the two superblock slots, frames (including the streaming encoder), the memory-map reader, and BlobId / BlobRef. The public module list is lib.rs. The code page quotes exports from that file.
persia-format implements the on-disk codecs (M1 done, 53/53). persia-storage implements the Storage trait, memory and local-file backends, and the single-file container (M2 done, 46/46). S3, GCS, and Azure have not been started (M12). persia-engine implements collection schema, documents, and manifests (M3 done, 15/15) and a segment builder, writer, and reader (M5 done, 48/48). Its write path is in progress (M6, 49/58): a memtable, a WAL with chunks, group commit, and replay, flush, commit, snapshots, auto-commit, and open checks, deletes and upserts across segments with tombstone sidecars, and segment merging (a merge policy, a segment merger, a background scheduler, and deletion of obsolete objects). Its query path is in progress (M7, 46/51): a query AST, user-text compiler, filter DSL, and query limits, collection statistics (document count, document frequency, average field length), BM25F scoring with static rank and score bounds, matching and score top-k over one view, and a collection search with sorts, pages, facets, and stored fields (CollectionViews::search). Relaxation has not been started (M8). A collection snapshot can be searched as library code. There is no search call on the database handle. persia-analysis implements tokenizers and the built-in analyzers de, en, es, fr, it, keyword, pt, standard, and whitespace (M4 done, 29/29). It does not search. persia-blob exports no API (M9 not started; its dependencies are done). The public persia crate exports no Db and no Collection. The crates are unpublished (publish = false, version 0.0.0).
Those crates are in the same git repository and are unpublished the same way. Depending on them does not give you Db::open.
Embedded full-text search in Rust
Section titled “Embedded full-text search in Rust”Illustrative public API. The block below is the SPEC sketch of persia::Db (SPEC §6.2, §7.1, §7.6, §8.1, and §9.6). It is not a stability promise. persia_engine::db::Database has open, create_collection, put, put_batch, delete, and commit. CollectionSnapshot::get fetches one document by id. CollectionViews::search runs a ranked search over a collection snapshot. There is no persia::Db, no search on the database handle, no put_struct, no put_blob, no get_blob, and no OpenOptions. Those SPEC names are not the public embedded API. The first release a caller is supposed to use is v0.1 (M10). That milestone is blocked on M6 (in progress), M7 (in progress), M8 (not started), and M9 (not started).
The shape a caller is meant to use:
// ILLUSTRATIVE — these methods are not in the persia crate.let db = persia::Db::open("app.persia")?;
// Schema is declared up front (SPEC §6.2). Adding a field later is allowed.// Changing a field's type is not.let products = db.create_collection(schema)?;
products.put(doc)?;products.commit()?;
// A typo still returns hits. The response says what changed (SPEC §7.6).let results = products.search("runing")?;let relaxation = &results.relaxation;The collection schema in SPEC §6.2, as JSON. CollectionSchema::from_json in persia-engine parses a schema. The block below is the SPEC sketch, and it does not open a database:
{ "name": "products", "fields": { "title": { "type": "text", "analyzer": "en", "boost": 3.0 }, "body": { "type": "text", "analyzer": "en" }, "brand": { "type": "keyword", "facet": true }, "price": { "type": "f64" }, "sales": { "type": "i64" } }, "ranking": { "static_rank": { "field": "sales", "weight": 0.1, "fn": "log1p" } }, "relaxation": { "enabled": true, "min_results": 1, "levels": "default", "fallback": "static_rank" }}Field types in that schema are text, keyword, i64, f64, bool, datetime, and stored (SPEC §6.1). Every document also has a string id (at most 512 bytes, unique in the collection). Documents are submitted as JSON, or as a serde struct via a planned put_struct, and stored as CBOR (SPEC §6.4).
put is an upsert by id. delete writes a tombstone. commit publishes a manifest. A put is specified to be visible to a later search on that database before commit (read-your-writes, SPEC §8.2–§8.4). One writer; a second writer fails immediately. Handles are specified as Send and Sync.
Search is specified to accept a text query or a structured query (SPEC §7.1): fields and boosts, filters, sort, limit / offset, facets, and relax. Scoring is BM25F plus an optional static rank (SPEC §7.2).
Relaxation
Section titled “Relaxation”Not started (M8). On by default in the design. The collection search is library code; this cascade is not, so a search that matches nothing returns no hits. If a query has fewer than min_results hits (default 1), the engine walks a cascade and stops at the first level that has enough hits (SPEC §7.6). The longer page is Typo-tolerant search.
| Level | Name | What changes |
|---|---|---|
| L0 | exact |
Every analyzed term is required |
| L1 | synonyms |
Collection synonyms, OR within a group |
| L2 | drop_terms |
Require fewer terms, dropping low-IDF terms first |
| L3 | prefix |
Prefix-expand terms of length at least 3 |
| L4 | fuzzy |
Edit distance 1 or 2, and report the corrected terms |
| L5 | fallback |
static_rank, or none |
Filters are not relaxed unless the caller sets relax.filters to "last_resort". relax: false on a query turns the cascade off.
The response is specified to carry what happened. This object is from SPEC §7.6. No function returns it today:
{ "level": "fuzzy", "applied": ["drop_terms:75%", "fuzzy"], "original": "zapatilas rojs", "effective": "zapatillas rojas", "corrected": { "zapatilas": "zapatillas", "rojs": "rojas" }}Command line
Section titled “Command line”Partly in the tree. persia inspect segment and persia dump segment read one segment file, and --verify checks it. persia verify checks a whole database. Still planned (ROADMAP 10.4): compact, stats, JSONL import, a one-shot search, and a small bench. The binary does none of those.
Common questions
Section titled “Common questions”The FAQ answers the same kind of question for status, how this differs from SQLite FTS5, Tantivy, and Meilisearch, the file format, crash safety, SDKs, and the license.
Can I add Persia to a Rust project today?
Section titled “Can I add Persia to a Rust project today?”Not as a database. The public persia crate exports no Db and no Collection. A search runs only through persia-engine (CollectionViews::search). The crates are unpublished (publish = false, version 0.0.0). You can depend on persia-format from git, as shown above, and on persia-storage, persia-engine, and persia-analysis. persia_engine::db::Database has open, create_collection, put, put_batch, delete, and commit. CollectionSnapshot::get fetches one document by id. CollectionViews::search runs a ranked search over a collection snapshot. There is no persia::Db, no search on the database handle, no put_struct, no put_blob, no get_blob, and no OpenOptions. Those SPEC names are not the public embedded API.
How do I open a database, index, and search?
Section titled “How do I open a database, index, and search?”You don’t, yet, through persia::Db::open. Those calls are the illustrative block on this page. persia_engine::db::Database has open, create_collection, put, put_batch, delete, and commit. CollectionSnapshot::get fetches one document by id. CollectionViews::search runs a ranked search over a collection snapshot. There is no persia::Db, no search on the database handle, no put_struct, no put_blob, no get_blob, and no OpenOptions. Those SPEC names are not the public embedded API. Below that API, persia_engine::db::Database opens a file, and the README quickstart searches it. The first release a caller is supposed to use is v0.1 (M10). That milestone is blocked on M6 (in progress), M7 (in progress), M8 (not started), and M9 (not started). PROGRESS.md is the checklist.
How do I read which relaxation was applied?
Section titled “How do I read which relaxation was applied?”On the intended API, from the search response field relaxation (SPEC §7.6): level, applied, original, effective, and corrected. Stricter levels rank above looser ones. Nothing in the repository computes this. See Typo-tolerant search.
Is the on-disk format stable?
Section titled “Is the on-disk format stable?”No. Format version 1.0 is a draft until the v1.0 release (SPEC §15). There is no compatibility promise. A change to the bytes requires a SPEC edit, a version or feature-flag bump, an ADR, and a golden fixture.
Is there a server, a cloud backend, or a client SDK?
Section titled “Is there a server, a cloud backend, or a client SDK?”Planned, not started. gRPC and HTTP are M11. S3, GCS, and Azure Blob are M12. Kubernetes sharding is M13. Rust and Go network clients are M14. Embedded Go and TypeScript bindings, which would open a file in-process, are a separate design (Embedded SDKs); they are not implemented either. Embedded mode, when it exists, has no authentication and no config file (SPEC §14).
Why is a query supposed to avoid empty results?
Section titled “Why is a query supposed to avoid empty results?”That is a product rule (SPEC §7.6), not an optional plugin. A query that matches nothing is relaxed step by step, and the response says what changed. Not started (M8). On by default in the design. The collection search it would wrap is library code. Typo-tolerant search separates the two.
Where is the source of truth?
Section titled “Where is the source of truth?”SPEC.md for behavior. ROADMAP.md for planned work. PROGRESS.md for what is done. This site is a reading of those files. For AI agents is the short version of the same constraints.