Query what is, what was, and what could be.
Query what is, what was, and what could be.
VevDB is a native embedded database with immutable database values, Datalog, queryable history, and hypothetical transactions.
- Runs in-process
- In-memory or durable
- macOS, Linux, Windows
Pseudocode Database as a value
current = database(connection)
// "current" is an immutable database valueproposed = with(current,
set task[42].status = approved
)
// "proposed" is another database value
query(current, task[42].status) // pending
query(proposed, task[42].status) // approved
// No write was performed.
// The connection still holds the original value.
query(
database(connection),
task[42].status
) // pending
Start with the problem you have.
You do not need to arrive wanting a new database paradigm. Start with history, a proposed change, or connected application data.
History / audit
What did the application know then?
Query an earlier point in time or inspect the complete history without maintaining a separate audit representation.
Explore queryable history What-if / planning
What would be true after this change?
Apply facts to an immutable database value, run queries or rules against the result, then keep it or discard it.
Explore hypothetical state Connected state
How is this application data related?
Query graph-like relationships with Datalog instead of accumulating one-off joins and traversal code.
Pass the whole database to a function.
Capture an immutable database value and pass it into ordinary application functions. It is a stable snapshot, not a copy of all its data. Each function sees one stable world, can query it freely, and returns data instead of performing I/O.
This makes a functional core and imperative shell a natural fit: decision logic receives `db` and a command; the shell owns the connection, transactions, and external effects.
Pseudocode Functional core / imperative shell
// Pure function: values in, values out
function decide(db, command):
allowed = query(db, rules_for(command))
if not allowed:
return rejection facts = facts_for(command)
next_db = with(db, facts)
effects = query(next_db, effects_to_emit)
return { facts, effects }
// Imperative shell: I/O stays at the boundary
db = database(connection)
result = decide(db, command)
transact(connection, result.facts)
send(result.effects)
Pass `decide` a current value, an earlier value, or a proposed value. The function itself does not change.
A component you can ship with the application
Embed VevDB in an application and open an in-memory or durable store. The database engine runs inside the application as a small native library.
VevDB fits applications where SQLite would be the natural choice for simple deployment, but the domain benefits from immutable database values, Datalog, queryable history, or hypothetical transactions. Use it from native software or through the Clojure and Java packages.
VevDB focuses on the embedded data model instead of growing into a database platform. That makes it a natural fit for self-contained desktop tools, developer products, on-premises applications, and resource-constrained single-node services.
3–4 MB native SDK downloads in v0.4.0
Embed it through a stable C ABI.
Embed VevDB directly through its stable C ABI or use a language package built on top. The database, query engine, and durable storage all run inside the application process.
C A complete in-process round trip
vev_conn_t conn = vev_conn_open_memory();const char *report = vev_transact_edn(
conn,
"[{:db/id 1 :project/name \"Atlas\"}]"
);
vev_string_free(report);
vev_value_handle_t rows = vev_query_value(
conn,
"[:find ?name :where "
"[?e :project/name ?name]]"
);
puts(vev_value_handle_edn(rows)); // #{["Atlas"]}
vev_value_handle_free(rows);
vev_conn_close(conn);
Not everything belongs in history.
VevDB also exposes the SQLite bundled into its native library, so an application can use both storage models without shipping another database dependency.
VevDB
Durable domain facts
Relationships, history, audit, business state, and data you want to query as immutable values.
Bundled SQLite API
Operational and derived state
Caches, sessions, jobs, email queues, search indexes, and other data that should be updated in place.
The two stores use separate database files. Transactions do not span both stores. Read the SQLite API guide.
The pieces for rich application state
Datalog queries
Query relationships with joins, rules, predicates, aggregates, negation, disjunction, and pull expressions.
Immutable snapshots
Hold and query stable database values while the connection continues accepting transactions.
History and time
Use historical views, `as-of`, `since`, and transaction-range reads.
Memory or disk
Open transient in-memory databases or durable stores backed internally by bundled SQLite.
Entity and index access
Use entities, lookup refs, pull, reverse references, range scans, and EAVT/AEVT/AVET/VAET indexes.
Native embedding
Use the stable C ABI directly or through a language package. The query engine and storage run in-process.
APIs
| Language | Status | Package or documentation | | -------- | --------- | --------------------------------------------------- | | C | Built in | C ABI guide | | Kvist | Built in | Kvist API | | Clojure | Available | vevdb/vev-clj | | Java | Available | vevdb/vev-java | | Odin | Available | vevdb/vev-odin |
Open a store. Transact facts. Query a value.
Start with the native SDK, the command-line interface, or a language package. VevDB is open source under EPL-2.0.
Read the getting started guide View source
$ vevdb transact example.db transactions.edn
$ vevdb query example.db query.ednTell us what you are building.
We would love to hear about projects where VevDB might be useful, whether you are actively evaluating it or simply exploring the model. If production is the goal, we are especially interested in what you would need before you could adopt it.
Email hello@vevdb.com Open a public GitHub issue
Email is private. The GitHub alternative opens a pre-filled public issue.
Go deeper
Getting started Open a database, transact data, and run a query. Data model Datoms, entities, attributes, transactions, and snapshots. Queries and pull Datalog clauses, inputs, rules, aggregates, and pull patterns. History Historical views, as-of, since, and transaction logs.

