Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

DriftDB

An append-only database with time-travel capabilities

DriftDB is an experimental database written in Rust that combines append-only storage with SQL:2011 temporal queries. It is designed for workloads where full audit history matters — audit logs, event sourcing, debugging, and analytics over historical snapshots.

Status: Alpha. The core engine and SQL interface work. Several higher-level features are partially implemented. See STATUS.md for details.


Key Concepts

Time-Travel Queries

Query your data at any past point in time using SQL:2011 temporal syntax:

-- As of a specific sequence number (reliable — sequences are immutable)
SELECT * FROM orders FOR SYSTEM_TIME AS OF @SEQ:1000;

-- As of a timestamp
SELECT * FROM users FOR SYSTEM_TIME AS OF '2025-10-24 12:00:00';

-- Full history for a row
SELECT * FROM users FOR SYSTEM_TIME ALL WHERE id = 'u1';

Append-Only Architecture

Every INSERT, UPDATE, and DELETE is stored as an immutable event. Nothing is ever overwritten. This gives you a built-in audit trail with zero extra configuration.

PostgreSQL Wire Protocol

DriftDB speaks the PostgreSQL wire protocol on port 5433, so standard PostgreSQL clients (psql, JDBC, etc.) can connect to it directly.


What Actually Works

  • Basic SQL: SELECT, INSERT, UPDATE, DELETE, CREATE TABLE
  • Time-travel queries by sequence number and timestamp
  • Full drift history per row (FOR SYSTEM_TIME ALL)
  • Subqueries, CTEs, JOINs, GROUP BY, ORDER BY
  • VACUUM (compact) and CHECKPOINT TABLE (snapshot)
  • ACID transactions with BEGIN / COMMIT / ROLLBACK
  • B-tree secondary indexes

Known Limitations

  • Table creation uses pk=id syntax instead of standard PRIMARY KEY (id)
  • No fsync after WAL writes — recent commits may be lost on crash
  • Replication framework exists but has no real consensus or failover
  • Most monitoring metrics are hardcoded placeholder values
  • Temporal JOINs not supported

Quick Start

# Build from source (requires Rust 1.70+)
cargo build --release

# Start the server
./target/release/driftdb-server --data-path ./data

# Or use the CLI directly
./target/release/driftdb init ./data
./target/release/driftdb sql --data ./data \
  -e 'CREATE TABLE users (pk=id, INDEX(name))'

Continue to the Quick Start guide →


Quick Start

Get up and running with DriftDB in under 5 minutes!

Installation

cargo install driftdb

Option 2: From Source

git clone https://github.com/davidliedle/DriftDB
cd DriftDB
cargo build --release
./target/release/driftdb --help

Option 3: Docker

docker pull driftdb/driftdb:latest
docker run -d -p 5432:5432 -v $(pwd)/data:/data driftdb/driftdb

Starting the Server

# Start with default settings
driftdb --data-dir ./mydata

# With custom port and logging
driftdb --data-dir ./mydata --port 5433 --log-level debug

The server will start and listen on localhost:5432 by default.

Your First Database

1. Connect to DriftDB

Using the CLI client:

# In another terminal
driftdb-cli

2. Create a Table

-- Standard SQL (recommended)
CREATE TABLE products (
    id TEXT PRIMARY KEY,
    name TEXT,
    price DECIMAL,
    created_at TIMESTAMP
);

-- Add an index after creation
CREATE INDEX ON products (name);

3. Insert Some Data

INSERT INTO products VALUES
    ('p1', 'Laptop', 999.99, '2025-10-25 10:00:00'),
    ('p2', 'Mouse', 29.99, '2025-10-25 10:05:00'),
    ('p3', 'Keyboard', 79.99, '2025-10-25 10:10:00');

4. Query Your Data

-- Simple query
SELECT * FROM products;

-- With filtering
SELECT * FROM products WHERE price < 100;

-- Aggregation
SELECT COUNT(*), AVG(price) FROM products;

Time-Travel Queries 🕐

This is where DriftDB shines! Query historical data effortlessly.

Query by Sequence Number

Every operation has a sequence number. Query at any point:

-- Get current sequence
SELECT MAX(__sequence) FROM products;

-- Query as of sequence 2 (after first 2 inserts)
SELECT * FROM products FOR SYSTEM_TIME AS OF @SEQ:2;

Query by Timestamp

-- See data as it was at 10:07 (only 2 products existed)
SELECT * FROM products FOR SYSTEM_TIME AS OF '2025-10-25 10:07:00';

Track Changes Over Time

-- Insert an update
UPDATE products SET price = 899.99 WHERE id = 'p1';

-- Query before the update
SELECT * FROM products FOR SYSTEM_TIME AS OF @SEQ:3;

-- Query after the update
SELECT * FROM products;

Using Transactions

BEGIN TRANSACTION;

INSERT INTO products VALUES ('p4', 'Monitor', 299.99, '2025-10-25 11:00:00');
UPDATE products SET price = price * 0.9 WHERE id = 'p4'; -- 10% discount

COMMIT;

Creating Indexes

Speed up your queries with indexes:

-- Create an index (with or without an explicit name)
CREATE INDEX ON products (price);
CREATE INDEX idx_price ON products (price);  -- named form

-- Queries using price will now be faster
SELECT * FROM products WHERE price > 50;

Using the Rust Client

use driftdb::client::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to DriftDB
    let client = Client::connect("localhost:5432").await?;

    // Execute a query
    let products = client.query("SELECT * FROM products WHERE price < ?", &[&100.0]).await?;

    for row in products {
        println!("Product: {} - ${}", row.get::<String>("name"), row.get::<f64>("price"));
    }

    Ok(())
}

Common Operations

Delete (Preserves History)

-- Delete a row (data still preserved in audit log)
DELETE FROM products WHERE id = 'p1';

Create a Snapshot

Snapshots speed up time-travel queries:

-- Create a snapshot at current state (PostgreSQL convention)
CHECKPOINT TABLE products;

Compact Old Data

-- Remove old event segments to reclaim space
VACUUM products;

Configuration

Common configuration options:

driftdb \
  --data-dir ./data \
  --port 5432 \
  --max-connections 100 \
  --enable-metrics \
  --log-level info

See Configuration for all options.

Next Steps

Now that you're up and running:

  1. Learn more SQL: See SQL Reference
  2. Time-Travel Deep Dive: Time-Travel Queries
  3. Deploy to Production: Deployment Guide
  4. Monitor Your Database: Monitoring

Getting Help


Having trouble? Check out the Troubleshooting Guide

Installation

First Steps

Basic Concepts

SQL Reference

Data Types

Queries

Time-Travel Queries

Transactions

Indexes

Client Libraries

Rust Client

Python Client

JavaScript/TypeScript

Performance Tuning

Query Optimization

Indexing Strategies

Snapshots & Compaction

Benchmarks

Deployment

Docker

Kubernetes

Bare Metal / systemd

Cloud Providers

Configuration

Server Options

Storage Settings

Security Settings

Performance Tuning

Monitoring & Observability

Metrics (Prometheus)

Logging

Health Checks

Grafana Dashboards

Backup & Recovery

Backup Strategies

Point-in-Time Recovery

Disaster Recovery

Replication

Setup & Configuration

Failover

Conflict Resolution

Authentication

MD5 Authentication

SCRAM-SHA-256

TLS/SSL

Authorization & RBAC

Role-Based Access Control

Row-Level Security

Encryption

Encryption at Rest

Key Management

TLS in Transit

Security Best Practices

Security Audit Report

Overview

Storage Engine

Append-Only Log

Segments & Frames

Snapshots

Compaction

Columnar Storage

Query Engine

Parser

Planner

Executor

Time-Travel

Transaction System

MVCC

Isolation Levels

WAL (Write-Ahead Log)

Indexing

B-Tree Indexes

Bloom Filters

Replication

Connection Pooling

Rate Limiting

Rust API

Engine

Query Types

Transactions

Client

Python API

JavaScript API

Building a Blog with DriftDB

Time-Travel Analytics

Audit Log System

Real-Time Dashboard

Common Issues

Performance Problems

Error Messages

Debugging Guide

Development Setup

Code Style

Testing

Pull Request Process

Glossary

Comparison with Other Databases

Roadmap

FAQ

License