history + time travel

Because DoltGres versions the whole database, every past state is still queryable. You can read a table as it looked at any commit, branch, or moment in time, walk the commit log, and ask “who changed this exact row, and to what?” — all in plain SQL.

an audit log you get for free

You do not have to build history tables, triggers, or change-data-capture. Every cell's full history is already recorded by the storage engine and queryable. The functions and tables on this page are how you read it.

time travel with AS OF

DoltGres supports SQL:2011-style AS OF. The operand is any valid reference — a commit hash, a branch name, or a timestamp — and it queries the table exactly as it existed at that point.

-- as of a specific commit hash
SELECT * FROM myTable AS OF 'kfvpgcf8pkd6blnkvv8e0kle8j6lug7a';

-- as of the head of another branch
SELECT * FROM myTable AS OF 'add-welcome-note';

-- as of a moment in time
SELECT * FROM myTable AS OF TIMESTAMP('2020-01-01');

-- even the schema is versioned
SHOW CREATE TABLE myTable AS OF 'add-welcome-note';

Each table in a query can carry its own AS OF— so you can join today's orders against last month's prices in a single statement to see how a number would have looked.

the commit log

The commit history lives in the dolt schema. Read it like any table, or use the DOLT_LOG table function when you want to scope the walk to specific refs.

-- full history reachable from the current HEAD
SELECT * FROM dolt.log;

-- commits before a date (columns: commit_hash, committer, email, date, message)
SELECT * FROM dolt.commits WHERE date < '2026-01-01';

-- table function: commits on main that are NOT on feat
SELECT * FROM DOLT_LOG('main', '--not', 'feat');

per-table history, diff & blame

Every user table gets a family of companion system tables — DoltGres builds them automatically, named after your table. These are the workhorses of data forensics.

system tablewhat it gives you
dolt_history_<table>Every version of every row across all commits — the full revision trail of the data.
dolt_diff_<table>Row-level changes with to_/from_ column pairs and a diff_type of added, modified, or removed.
dolt_commit_diff_<table>The diff between any two commits or branches — you pass the two refs as filters.
dolt_blame_<table>Who last changed each row, in which commit, when, and with what message.
-- the full history of one row's every value
SELECT * FROM dolt_history_employees WHERE id = 0 ORDER BY commit_date;

-- only the rows that were modified
SELECT * FROM dolt_diff_employees WHERE diff_type = 'modified';

-- diff one table between two refs (here: main vs the feat branch)
SELECT * FROM dolt_commit_diff_employees
WHERE from_commit = 'main' AND to_commit = 'feat';

-- who last touched each row
SELECT * FROM dolt_blame_employees LIMIT 5;

In a dolt_diff_<table> row, uncommitted working-set changes show up with to_commit = 'WORKING', so you can inspect pending edits the same way you inspect committed ones.

diff table functions

When you want a diff scoped by ref rather than reading the per-table system table, DoltGres ships table functions that return rows. Pass the two refs and (where relevant) a table name.

-- the per-row diff of mytable between two branches
SELECT * FROM DOLT_DIFF('main', 'feat', 'mytable');

-- a per-table summary of rows added / modified / deleted
SELECT * FROM DOLT_DIFF_STAT('main', 'feat');

-- a high-level "which tables changed" summary
SELECT * FROM DOLT_DIFF_SUMMARY('main', 'feat');

what to read next