An application can have customer records, uploaded documents, full-text search, and semantic search over those documents. Keeping the data, permissions, and updates consistent across those features can become a project of its own.
I've built HexDB to bring those pieces closer together.
HexDB is an encrypted, replicated database for JSON documents and binary files, with full-text and vector search. The core server is written in Rust and runs as one binary.
I'm Matthew "Doc" Martin, a software architect with more than 25 years in software development. HexDB is my independent project, built during late nights and weekends alongside my day job. With versions 2.4.3 and 2.4.4 released, this seems like a good time to introduce it here.
Documents and files in one database
HexDB stores JSON documents in collections called tessellations. You can query them through REST, GraphQL, gRPC, or SQL, with drivers for Node.js, Python, .NET, Java through JDBC, and ODBC.
SQL currently supports reads. Writes go through the APIs and drivers.
Files are part of the database too. They have queryable metadata, version history, resumable uploads, and access controls. Their content is encrypted, deduplicated, and compressed when that helps.
Consider an application with customer records and uploaded invoices. You need to find the records, retrieve the files, restrict access, and perhaps search the invoices by their contents. HexDB provides those capabilities within the same database platform.
It also includes an admin UI for managing documents, files, users, indexes, and the cluster. I want the operational side to be approachable, including when you're the person building the application and keeping it running.
Vector search alongside ordinary queries
Vector search is an index type in HexDB. You can supply your own embeddings or configure an embedding provider and have HexDB generate them from selected fields.
Similarity searches use the same documents, permissions, row filters, and field masks as other queries. You can combine a semantic search with an ordinary filter.
For example, after configuring an embedding provider and a vector index on an articles collection, this request searches published articles by meaning:
curl -X POST http://localhost:7700/articles/_query \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filter": { "status": "published" },
"near": {
"field": "embedding",
"text": "storage engines for edge devices",
"k": 5
}
}'
The same approach works with extracted text from uploaded files. A search can find a document by what it discusses, even when its filename isn't useful.
Automatic embeddings use the provider you configure, including supported local providers. The selected source text goes to that provider. Usage controls include per-user allowances and a monthly token budget.
Each HexDB server also exposes an MCP endpoint for authenticated, read-only access by external agents. Optional A2A support lets another agent delegate a question to HexDB's own chat system. Those lookups run with the calling user's permissions.
Security around both records and uploads
My work in payments influences the questions I ask about data handling: who can read a value, where it gets copied, and what remains after a request finishes.
HexDB includes encryption at rest, role-based access, row filters, field masking, MFA, and an audit trail. Schema-defined tokenization can replace sensitive field values before the document reaches its write-ahead log, storage, replicas, or backups.
There are two tokenization modes. One-way tokens support matching without recovering the original value. Vault tokens keep the original in a separate encrypted vault, with explicit permission and auditing for detokenization.
File uploads also have integrated malware scanning and quarantine. YARA-X is built into supported builds, and HexDB connects to a separately running ClamAV daemon for signature-based scanning. Files flagged by a scanner are quarantined instead of becoming normal downloadable files or being replicated.
That distinction matters for deployment: the core database is one binary; ClamAV is an additional service. The supplied Docker Compose and Helm configurations include it.
The latest release adds cluster-wide IP blocking with optional expiry, signed responses between servers, and overwriting sensitive decrypted field values in memory when requests finish using them. It also fixes a change-feed issue so users cannot learn about deletions of records they weren't allowed to see.
A foreign key question that changed the engine
One of the changes in 2.4.3 began with a prospect asking about foreign keys.
HexDB now supports optional foreign keys in document schemas. With enforcement enabled, a write referencing a missing parent is refused.
The interesting part is when that check happens.
Suppose an order references a customer:
- A request checks that the customer exists.
- Another request deletes that customer.
- The first request commits the order.
A successful check at step one isn't enough to prevent an orphan at step three.
HexDB checks the relationship as part of the commit itself. Cascading deletes also re-check for newly written children at commit time, closing a related race.
The CLI gained document, transaction, and schema operations with idempotency keys, so retrying after a dropped connection won't apply the same write twice. A new “Writing safely” manual section explains the guarantees for inserts, updates, upserts, deletes, and transactions.
This is the kind of feedback I want from people evaluating HexDB. A concrete application requirement can expose something worth changing in the engine.
Recovery and performance in the latest releases
A group of HexDB servers is called a lattice. One server, the Overseer, handles writes; eligible replicas can take over if it fails.
Version 2.4.4 brings failover down to 15–20 seconds, about half the previous time. It also addresses isolated servers electing themselves and servers disagreeing about leadership when the whole cluster starts together.
Hosted routing now sends traffic only to servers that have the data. In one provisioning run, a new three-region hosted lattice went from nothing to fully ready in 33 seconds.
Storage and query improvements include:
| Measurement | Before | After |
|---|---|---|
| Small-record storage in the measured workload | 177 bytes | 40 bytes |
| GROUP BY over 100,000 documents | 320 ms | 210 ms |
The storage improvement comes from per-file compression dictionaries that capture patterns shared by documents. Reading a stored document also takes about half the work.
These are measurements from the specific workloads used for the release. They give a useful starting point for evaluating the changes against your own data.
Try HexDB and tell me what you find
HexDB is available through npm, PyPI, NuGet, Maven, Homebrew, Chocolatey, Debian packages, and Docker. You can run it yourself or explore hosted lattices.
The repository has installation instructions, examples, and the technical manual:
I'd like to hear from developers working with documents, uploaded files, sensitive fields, or semantic search. What would you need to test before considering HexDB for an application? Which integration would make it easier to evaluate?
The foreign-key question already changed the engine. I'm interested in the next question.
Top comments (0)