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 value

proposed = 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.

Explore Datalog queries

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.

Read the article

  • The same function can receive current, historical, or hypothetical state.
  • Tests pass in a database value without giving the core a live connection.
  • Long-running work can keep a stable snapshot while new transactions arrive.
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.

Read the C ABI guide

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.

  • Datalog and pull
  • Queryable history
  • Hypothetical transactions

Bundled SQLite API

Operational and derived state

Caches, sessions, jobs, email queues, search indexes, and other data that should be updated in place.

  • Ordinary SQL
  • FTS5 included
  • No additional native library

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

LanguageStatusPackage or documentation
CBuilt inC ABI guide
KvistBuilt inKvist API
ClojureAvailablevevdb/vev-clj
JavaAvailablevevdb/vev-java
OdinAvailablevevdb/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.

$ vevdb transact example.db transactions.edn
$ vevdb query example.db query.edn

Tell 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 is private. The GitHub alternative opens a pre-filled public issue.

Go deeper