Recover Data from Version History

Open inAnthropic

Every write in TerminusDB creates an immutable commit. Data is never lost — only the branch HEAD moves forward. This tutorial shows how to use the commit log to identify a known-good state and reset your branch to recover from a bad change.

Time: ~10 minutes Prerequisites: TerminusDB running on localhost:6363 (Install guide →)

Setup

Example: Bash
export AUTH="admin:root"
export SERVER="http://localhost:6363"
export DB="admin/MyDatabase"

Step 1 — Create a database with initial data

Create the database:

Loading…

Insert an initial document:

Loading…

Step 2 — Make a second commit (the "good" state)

Update the product price — this creates a second commit that we will later identify as "last known good":

Loading…

Step 3 — Make a bad change (simulate data corruption)

Delete the product entirely — this is the change we want to recover from:

Loading…

Verify it is gone:

Loading…

You should get an empty response or an error — the document no longer exists on main.

Step 4 — View the commit log

Use the /api/log/{path} endpoint to list recent commits:

Loading…

Expected output:

Example: JSON
[
  {
    "@id": "ValidCommit/<sha-of-delete-commit>",
    "@type": "ValidCommit",
    "author": "admin",
    "identifier": "<sha-of-delete-commit>",
    "instance": "layer_data:Layer_<hash>",
    "message": "Accidentally deleted product",
    "parent": "ValidCommit/<sha-of-good-commit>",
    "schema": "layer_data:Layer_<hash>",
    "timestamp": 1714400000.0
  },
  {
    "@id": "ValidCommit/<sha-of-good-commit>",
    "@type": "ValidCommit",
    "author": "admin",
    "identifier": "<sha-of-good-commit>",
    "instance": "layer_data:Layer_<hash>",
    "message": "Update widget price to 12.50",
    "parent": "ValidCommit/<sha-of-first-commit>",
    "schema": "layer_data:Layer_<hash>",
    "timestamp": 1714399900.0
  },
  {
    "@id": "ValidCommit/<sha-of-first-commit>",
    "@type": "InitialCommit",
    "author": "admin",
    "identifier": "<sha-of-first-commit>",
    "instance": "layer_data:Layer_<hash>",
    "message": "Add initial product data",
    "schema": "layer_data:Layer_<hash>",
    "timestamp": 1714399800.0
  }
]

The response includes additional internal fields: @id (commit IRI), instance and schema (storage layer references), and parent (link to previous commit, absent on the initial commit). For recovery purposes, focus on identifier, message, and timestamp.

Identify the commit you want to return to. In this case it is the second commit ("Update widget price to 12.50"). Copy its identifier value.

Reading timestamps

Timestamps are Unix epoch seconds. Convert to human-readable with: date -d @1714399900 (Linux) or date -r 1714399900 (macOS).

Step 5 — Create a branch from the good commit (verify before reset)

Before resetting main, create a branch from the good commit to inspect the data safely:

Example: Bash
curl -s -u $AUTH -X POST \
  "$SERVER/api/branch/$DB/local/branch/recovery-check" \
  -H "Content-Type: application/json" \
  -d '{"origin": "admin/MyDatabase/local/commit/<sha-of-good-commit>"}'

Replace <sha-of-good-commit> with the actual identifier from your log output.

Step 6 — Verify the data on the recovery branch

Query the recovery branch to confirm it contains the expected data:

Example: Bash
curl -s -u $AUTH \
  "$SERVER/api/document/$DB/local/branch/recovery-check?id=terminusdb:///data/product-001&raw_json=true" | jq

Expected: The document is present with "price": 12.50.

Step 7 — Reset main to the good commit

Now that we have confirmed the data is correct, reset main to the good commit:

Example: Bash
curl -s -u $AUTH -X POST "$SERVER/api/reset/$DB" \
  -H "Content-Type: application/json" \
  -d '{"commit_descriptor": "admin/MyDatabase/local/commit/<sha-of-good-commit>"}'

Expected response:

Example: JSON
{"@type": "api:ResetResponse", "api:status": "api:success"}

Step 8 — Confirm the recovery

Verify that main now has the document restored:

Example: Bash
curl -s -u $AUTH "$SERVER/api/document/$DB?id=terminusdb:///data/product-001&raw_json=true" | jq

Expected: The document is present with "price": 12.50 and "status": "active".

Cleanup

Loading…

What you learned

  • Every write creates an immutable commit — data is never lost, only HEAD moves forward
  • The commit log is the audit trailauthor, message, and timestamp on every commit
  • Reset moves the branch HEAD backward — it does not delete commits from history
  • Branch from a commit to inspect safely — verify before resetting production data

Next steps

Was this helpful?