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) andCHECKPOINT TABLE(snapshot)- ACID transactions with
BEGIN/COMMIT/ROLLBACK - B-tree secondary indexes
Known Limitations
- Table creation uses
pk=idsyntax instead of standardPRIMARY 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 →
Links
- GitHub: github.com/davidliedle/DriftDB
- License: MIT
Quick Start
Get up and running with DriftDB in under 5 minutes!
Installation
Option 1: Using Cargo (Recommended)
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:
- Learn more SQL: See SQL Reference
- Time-Travel Deep Dive: Time-Travel Queries
- Deploy to Production: Deployment Guide
- Monitor Your Database: Monitoring
Getting Help
- 📖 Read the User Guide
- 💬 Ask questions in GitHub Discussions
- 🐛 Report bugs on GitHub Issues
Having trouble? Check out the Troubleshooting Guide