# Turso VDBE Bytecode Interpreter Architecture: How Query Execution Works

> Explore Turso's VDBE bytecode interpreter architecture. Understand how it executes SQL queries asynchronously. Learn about high concurrency without blocking threads.

- Repository: [Turso Database/turso](https://github.com/tursodatabase/turso)
- Tags: architecture
- Published: 2026-06-22

---

**Turso’s VDBE is a register-based virtual machine that executes SQL queries by asynchronously stepping through bytecode instructions, yielding control during I/O operations to enable high concurrency without blocking threads.**

Turso’s Virtual Database Engine (VDBE) implements a bytecode interpreter that powers SQL query execution in the `tursodatabase/turso` repository. Modeled after SQLite’s virtual machine but engineered for asynchronous, serverless environments, this architecture compiles SQL into a sequence of register-based instructions. The engine executes these instructions through a stepping loop that pauses for non-blocking I/O, allowing thousands of concurrent queries to share the same runtime resources.

## Core Architecture Components

### Program and ProgramState

The VDBE operates on two primary structures defined in [`core/vdbe/mod.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/mod.rs). The **`Program`** struct holds the compiled bytecode sequence as a vector of `Insn` opcodes, alongside cursor descriptors and execution metadata. The **`ProgramState`** struct maintains the runtime context, including a flat array of registers (`ProgramState.registers`), active cursors, I/O completion handlers, transaction bookkeeping, and the program counter (`pc`).

### Instructions and Opcode Dispatch

Each bytecode operation is represented by the **`Insn`** enum in [`core/vdbe/insn.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/insn.rs), defining variants like `Add`, `Jump`, `OpenRead`, and `Column` with their operands (`P1` through `P5`). The actual implementation lives in [`core/vdbe/execute.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/execute.rs) as **`InsnFunction`**, a function pointer type that maps each opcode to its execution logic. The dispatch mechanism occurs in `execute::run_program_step`, which matches the current opcode and invokes the corresponding function.

### Register-Based Execution

Unlike stack-based virtual machines, Turso’s VDBE uses a register file where instructions read and write values directly. Each register holds a `Value`, an aggregate context, or a record blob. For example, the `Add` opcode implemented in [`execute.rs`](https://github.com/tursodatabase/turso/blob/main/execute.rs) (lines 81‑88) reads two source registers, performs the addition, and writes the result to a destination register:

```rust
pub fn op_add(... ) -> Result<InsnFunctionStepResult> {
    load_insn!(Add { lhs, rhs, dest }, insn);
    state.registers[*dest].set_value(
        state.registers[*lhs].get_value()
            .exec_add(state.registers[*rhs].get_value()),
    );
    state.pc += 1;
    Ok(InsnFunctionStepResult::Step)
}

```

### Asynchronous I/O and State Management

To support high concurrency, the VDBE never blocks on disk or network operations. Instead, opcodes that require I/O return **`InsnFunctionStepResult::IO(io_completions)`**, allowing the outer driver to yield control. The **`ActiveOpStateSlot`** structure preserves intermediate state across these yields for long-running operations like hash joins or `VACUUM`. This re-entrant design enables the interpreter to pause mid-instruction and resume after the async runtime completes the I/O.

## Query Execution Flow

The VDBE executes queries through a five-phase pipeline:

1. **Compilation** – The SQL parser generates an AST, and the translator (`core/translate/*.rs`) walks the tree to emit a sequence of `Insn` objects.
2. **Program Initialization** – `Program::new` allocates a `ProgramState` with sufficient registers and cursors for the specific statement.
3. **Stepping Loop** – The driver repeatedly calls `execute::run_program_step`, which fetches the current instruction via `state.pc`, dispatches to the matching `InsnFunction`, and updates the program counter.
4. **Yield and Resume** – When an instruction returns an `IO` result, the outer async runtime waits on the `IOCompletions` object, then re-invokes the step function to resume execution.
5. **Result Production** – Upon reaching the `Halt` opcode, the VDBE extracts the final row from `state.result_row` and returns it to the client.

## Transaction Handling and MVCC Integration

The VDBE integrates tightly with Turso’s multi-version concurrency control (MVCC) system. When a statement begins, `ProgramState.begin_statement` establishes a sub-journal or MVCC savepoint. The **`CommitState`** enum (defined in [`core/vdbe/mod.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/mod.rs) lines 173‑194) manages the asynchronous commit pipeline through three phases: `Ready` for normal execution, `Committing` while waiting for WAL flushes, and `CommittingMvcc` during MVCC checkpointing. This state machine yields `IO` results back to the driver rather than blocking the interpreter thread.

## Example: Running a Query Through the VDBE

The following Rust example demonstrates how high-level API calls translate into VDBE bytecode execution:

```rust
use turso::{Connection, Result};

fn run_example() -> Result<()> {
    // Open a connection; the async-compatible pager initializes the VDBE environment
    let mut conn = Connection::open("file:mydb.sqlite")?;

    // Prepare triggers translation: SQL → AST → bytecode in core/vdbe/mod.rs
    let mut stmt = conn.prepare("SELECT name, age FROM users WHERE age > ?")?;

    // Bind writes the parameter value into a register
    stmt.bind(1, 30i64)?;

    // Step drives the VDBE stepping loop, handling yielded IO transparently
    while let Some(row) = stmt.step()? {
        let name: String = row.get_text(0)?.to_string();
        let age: i64 = row.get_int(1)?;
        println!("User: {name}, age {age}");
    }

    Ok(())
}

```

This example illustrates how `Connection::prepare` invokes the bytecode generator, `stmt.bind` populates registers, and `stmt.step` executes the interpreted program while managing asynchronous I/O internally.

## Key Source Files Reference

Understanding the VDBE architecture requires examining these specific files in the `tursodatabase/turso` repository:

- **[`core/vdbe/mod.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/mod.rs)** – Defines `Program`, `ProgramState`, `CommitState`, `ActiveOpStateSlot`, and the async commit state machine.
- **[`core/vdbe/insn.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/insn.rs)** – Enumerates the `Insn` opcode variants and their operand structures.
- **[`core/vdbe/execute.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/execute.rs)** – Implements opcode functions (`op_add`, `op_jump`, `op_open_read`) and the `return_if_io!` macro for async handling.
- **`core/translate/*.rs`** – Bytecode generation modules that convert AST nodes into `Insn` sequences.
- **[`core/vdbe/metrics.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/metrics.rs)** – Collects execution statistics (instruction counts, rows read) for `EXPLAIN` output.
- **[`core/vdbe/explain.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/explain.rs)** – Generates human-readable query plans by walking instruction lists.
- **[`core/vbde/hash_table.rs`](https://github.com/tursodatabase/turso/blob/main/core/vbde/hash_table.rs)** – Supports hash-join and distinct operations via `ProgramState.hash_tables`.
- **[`core/vdbe/value.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/value.rs)** – Defines the `Value` type and arithmetic primitives (`exec_add`, `exec_subtract`).

## Summary

- **Turso’s VDBE** is a register-based virtual machine modeled after SQLite but optimized for asynchronous execution.
- **Bytecode instructions** are defined as `Insn` enums and implemented via `InsnFunction` pointers in [`core/vdbe/execute.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/execute.rs).
- **Register-based execution** operates on a flat array in `ProgramState.registers`, avoiding stack overhead.
- **Non-blocking I/O** is achieved by returning `IO` results from opcodes, allowing coroutine-style yield/resume semantics.
- **MVCC integration** uses `CommitState` to manage transaction commits asynchronously without blocking the interpreter.

## Frequently Asked Questions

### How does Turso's VDBE differ from SQLite's virtual machine?

While Turso’s VDBE maintains opcode compatibility with SQLite and uses a similar register-based design, it fundamentally differs by implementing **non-blocking I/O semantics**. According to the `tursodatabase/turso` source code, any opcode that would block in SQLite (such as disk reads or WAL checkpoints) instead returns `InsnFunctionStepResult::IO`, enabling the engine to run thousands of concurrent queries on a single thread without blocking.

### What happens when a VDBE instruction needs to perform I/O?

When an instruction like `OpenRead` or `Commit` encounters a cache miss or requires WAL flushing, the corresponding function in [`core/vdbe/execute.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/execute.rs) returns `InsnFunctionStepResult::IO(io_completions)`. The outer stepping loop yields control to the async runtime, which processes the I/O completion. Once the operation finishes, the runtime resumes execution by calling `execute::run_program_step` again, with the `ProgramState` preserving the exact program counter and register values.

### Why does the VDBE use a register-based architecture instead of a stack?

The register-based design, using `state.registers` as a flat array indexed by operand values, provides **O(1) access** to values and eliminates the overhead of stack manipulation. This approach aligns with SQLite’s implementation and allows the bytecode generator in `core/translate/*.rs` to optimize value reuse by keeping frequently accessed data in specific registers across multiple instructions.

### How does the VDBE handle transaction commits asynchronously?

Transaction commits are managed by the **`CommitState`** enum in [`core/vdbe/mod.rs`](https://github.com/tursodatabase/turso/blob/main/core/vdbe/mod.rs) (lines 173‑194). The state machine transitions from `Ready` to `Committing` when a transaction ends, then yields `IO` results while waiting for the pager to flush or MVCC checkpointing to complete. This design ensures that the `COMMIT` opcode never blocks the interpreter thread, allowing other queries to execute while the storage layer persists data.