We're excited to share an early preview of a powerful new feature in Turso's SQLite rewrite: built-in Change Data Capture (CDC). While still unstable and under active development, it's ready for testing and we'd love your feedback and contributions.
Change Data Capture is a pattern for tracking and recording changes to your database in real-time. Instead of periodically scanning tables to find what changed, CDC automatically logs every insert, update, and delete as it happens. This creates an audit trail that's invaluable for:
Our implementation makes CDC a first-class citizen in SQLite. You enable it with a simple pragma:
PRAGMA unstable_capture_data_changes_conn('full');
Once enabled, every data change on that connection gets logged to a CDC table:
CREATE TABLE turso_cdc (
change_id INTEGER PRIMARY KEY AUTOINCREMENT,
change_time INTEGER, -- Unix timestamp
change_type INTEGER, -- -1=delete, 0=update, 1=insert
table_name TEXT,
id, -- rowid of affected row
before BLOB, -- row data before change
after BLOB -- row data after change
)
We've designed multiple modes to balance between detail and performance:
id
— Logs only the rowid, keeping the CDC table compactbefore
— Captures row state before updates and deletesafter
— Captures row state after inserts and updatesfull
— Captures both before and after statesHere's what it looks like in action:
-- Enable full CDC mode
PRAGMA unstable_capture_data_changes_conn('full');
--- Custom table name
--- PRAGMA unstable_capture_data_changes_conn('full,custom_cdc_table');
-- Make some changes
PRAGMA unstable_capture_data_changes_conn('full');
CREATE TABLE t(a INTEGER PRIMARY KEY, b);
INSERT INTO t VALUES (1, 2), (3, 4);
UPDATE t SET b = 20 WHERE a = 1;
UPDATE t SET a = 30, b = 40 WHERE a = 3;
DELETE FROM t WHERE a = 1;
-- Query the CDC log with our JSON helper functions
SELECT
id,
change_type,
bin_record_json_object(table_columns_json_array('users'), before) AS before,
bin_record_json_object(table_columns_json_array('users'), after) AS after
FROM turso_cdc;
This gives you a complete history of changes in an easily queryable format:
SELECT change_type, id,
bin_record_json_object(table_columns_json_array('t'), before) before,
bin_record_json_object(table_columns_json_array('t'), after) after
FROM turso_cdc;
┌─────────────┬────┬────────────────────┬────────────────────┐
│ change_type │ id │ before │ after │
├─────────────┼────┼────────────────────┼────────────────────┤
│ 1 │ 1 │ │ {"a":1,"b":2} │
│ 1 │ 3 │ │ {"a":3,"b":4} │
│ 0 │ 1 │ {"a":1,"b":2} │ {"a":1,"b":20} │
│ -1 │ 3 │ {"a":3,"b":4} │ │
│ 1 │ 30 │ │ {"a":30,"b":40} │
│ -1 │ 1 │ {"a":1,"b":20} │ │
└─────────────┴────┴────────────────────┴────────────────────┘
One important limitation to be aware of: if you change your table schema (adding/dropping columns), the table_columns_json_array()
function will return the current schema, not the historical one. This can lead to incorrect results when decoding older CDC records.
For example, if you drop a column, using bin_record_json_object(table_columns_json_array('users'), before)
on historical records will shift the column mappings and produce incorrect JSON. As a workaround, you can manually track schema versions by storing the output of table_columns_json_array()
before making schema changes.
Built-in CDC opens up exciting possibilities:
We've made some intentional choices in this implementation:
This feature is marked as unstable because we're still iterating on the API and functionality. We expect breaking changes as we incorporate feedback and add features like:
But that's exactly why we need you to try it! Test it with your workloads, push its limits, and let us know what works and what doesn't.
curl -sSL tur.so/install | sh
While CDC is the headline feature, v0.1.2 brings many other improvements:
We've added Euclidean distance support for vector search, opening the door for AI and similarity search use cases right in your database.
Database.open
functionalityfind_cell()
for faster lookupsWe're building this in the open and welcome contributions. Whether it's testing edge cases, suggesting API improvements, or submitting PRs, your input will shape how CDC works in Turso.
Check out the implementation PRs to see the technical details, report issues, or contribute code. Together, we can make CDC a killer feature that sets Turso apart.
Ready to capture some changes? 🚀
curl -sSL tur.so/install | sh