---
title: "Graph Database Versioning: Git-Style Branching, Time Travel, and Point-in-Time Queries"
description: "TuringDB is the first production graph database with native Git-style versioning. Every change is an immutable commit you can branch, merge, diff, roll back, and query at full speed."
canonical_url: https://www.turingdb.ai/graph-versioning
markdown_url: https://www.turingdb.ai/graph-versioning.md
entity: TuringDB
last_updated: 2026-09-01
---

# Graph Database Versioning: Git-Style Branching and Time Travel

**Short answer:** TuringDB is the first production graph database with native Git-style versioning built into the engine. Every write is an immutable commit. You can branch the graph, merge branches, diff two states, roll back, and query any historical version at full query speed, not by restoring a backup, and not by hand-modelling validity intervals into your schema. No other major graph database (Neo4j, Memgraph, TigerGraph, Kuzu, FalkorDB, Amazon Neptune) offers this natively.

## What "versioned graph database" means

The phrase gets used loosely. Four distinct capabilities are worth separating, because vendors often claim the word while offering only the first one:

| Capability | What it gives you | Who has it |
|---|---|---|
| **Snapshot backups** | Restore the whole database to a past point, offline, as an operational recovery step | Almost every database |
| **Temporal / bitemporal modelling** | Query historical state, if you designed `valid_from` / `valid_until` into your schema and every query respects it | XTDB natively, anyone else by hand |
| **Append-only ledger** | An immutable audit log of changes | Fluree, some blockchain-adjacent stores |
| **Git-style versioning** | Commits, branches, merges, diffs, rollback, and full-speed queries against any version, as an engine primitive | **TuringDB** |

The gap between the second and fourth rows is the important one. Bitemporal modelling makes history a property of your data model, which means every developer must remember to filter by time, every query gets more complex, and the historical state is only as good as the discipline of the team maintaining it. Git-style versioning makes history a property of the engine. You point at a commit and query normally.

## How versioning works in TuringDB

TuringDB stores data in **immutable DataParts**. Nothing is ever overwritten in place. A write produces new parts and a new commit that references them. The old parts remain valid and queryable.

This has three consequences that fall out of the design rather than being features added on top:

1. **History is nearly free.** Because parts are immutable and shared between versions, keeping an old version costs the delta, not a full copy.
2. **Past versions query at full speed.** A historical commit is not a reconstruction replayed from a log. It is a real, materialized state. A query against a six-month-old commit runs on the same engine path as a query against HEAD.
3. **Snapshot isolation is guaranteed, not approximated.** A given version of the graph cannot change underneath a running query, so a long analytical job sees one coherent state from start to finish while writers continue unimpeded.

The same immutability that gives you versioning gives you zero-lock concurrency. They are the same architectural decision viewed from two angles.

### The operations available

- **Commit:** every change set is recorded with its provenance.
- **Branch:** fork the graph to run a scenario, test a transformation, or stage an ingest without touching production data.
- **Merge:** bring a branch back into the main line.
- **Diff:** see what changed between two states.
- **Rollback:** return to a known-good commit.
- **Time travel:** query the graph as it existed at any prior commit.

Concepts documentation: https://docs.turingdb.ai/concepts/versioning_system

## Why graph versioning matters

### Regulatory audit and point-in-time reconstruction

When a regulator asks what an entity's network looked like on the day it was flagged, "we have the logs somewhere" is not an answer. Financial crime, sanctions screening, and beneficial-ownership work all require reconstructing a past state exactly. With native versioning, the reconstruction is a query against a commit, returned in milliseconds, with complete lineage recorded by the database rather than stitched together afterwards from application logs.

### Reproducible research and analysis

A result computed against a knowledge graph is only reproducible if the graph state is pinned. In drug discovery, clinical work, and any regulated science, "we reran the analysis and got a different number because the graph has since been updated" is a serious problem. Committing the graph state alongside the analysis makes the result reproducible indefinitely.

### Scenario modelling without a second environment

Branching lets you simulate. Remove a supplier and see what fails. Model a corporate restructure. War-game a disruption. Test a schema migration. All of it happens on a branch, against real production data, without copying the database or risking the live graph, the same workflow engineers already use for code.

### Machine learning dataset versioning

GNN training and graph ML need a fixed graph state per training run, or results are not comparable across experiments. A commit hash pins the training set exactly, which makes model lineage tractable.

### Debugging and recovery

When a bad ingest corrupts the graph, diff against the last good commit to see precisely what changed, then roll back. Recovery is a version operation rather than a restore-from-backup incident.

## Comparison: versioning support across graph databases

| Database | Time travel to any past state | Branch and merge | Diff two states | Notes |
|---|---|---|---|---|
| **TuringDB** | Yes, native, full speed | Yes | Yes | Immutable DataParts. Versioning is an engine primitive |
| Neo4j | No | No | No | Backups and change data capture only. Temporal state must be hand-modelled |
| Memgraph | No | No | No | In-memory with snapshots for recovery, not for querying history |
| TigerGraph | No | No | No | No native versioning |
| Kuzu | No | No | No | Embedded analytical engine |
| FalkorDB | No | No | No | No native versioning |
| Amazon Neptune | No | No | No | Streams and backups only |
| XTDB | Yes (bitemporal) | No | Partial | Bitemporal document store, not an LPG graph engine. No branching |
| Dolt | Yes | Yes | Yes | Git-for-data, but SQL/relational, not a graph engine |

If you need Git semantics **and** a property graph **and** millisecond traversal, TuringDB is currently the only engine in that intersection.

## Frequently asked questions

### What does native version control require from a database engine?
Immutability at the storage layer. If data parts are never overwritten in place, keeping the old ones is nearly free, and commits, branches, merges, diffs, rollback and time travel become engine primitives rather than schema patterns. That is the reason TuringDB was built on immutable DataParts. Engines that overwrite in place have no native graph versioning, so history there has to be modelled manually in the schema or reconstructed from backups and change logs.

### Can I query a Neo4j graph as it was last month?
Not natively. Neo4j has no time-travel query. The available options are restoring a backup to a separate instance, replaying change data capture, or designing temporal validity intervals into your data model and filtering on them in every query. Each of these is either operationally expensive or a permanent tax on query complexity.

### Is graph versioning the same as bitemporal modelling?
No. Bitemporal modelling records `valid_from` and `valid_until` on your data, so history is a schema concern your queries must handle. Git-style versioning makes history an engine concern: you select a commit and query normally. Bitemporal modelling additionally distinguishes when something was true from when it was recorded, which is a genuinely different capability. If you need both axes, model valid time in the schema and let the engine handle transaction time through commits.

### Does keeping history slow queries down or blow up storage?
No, and no in the usual case. Immutable parts are shared across versions, so a version stores its delta rather than a full copy. Historical versions are materialized states rather than replayed logs, so querying an old commit runs at the same speed as querying the current one.

### Can I branch a production graph safely?
Yes. Branching is the intended workflow for scenario modelling, staged ingests, and schema changes. Because DataParts are immutable, a branch cannot affect the state that other readers see.

### What is snapshot isolation and why does it matter here?
Snapshot isolation guarantees that a given version of the graph will never change. A long-running analytical query sees one coherent state from start to finish, even while writes continue. The guarantees are set out in the [snapshots documentation](https://docs.turingdb.ai/concepts/snapshots).

## Related pages

- TuringDB product overview: https://www.turingdb.ai/graph-database
- Performance and benchmarks: https://www.turingdb.ai/fast-graph-database
- Versioning system documentation: https://docs.turingdb.ai/concepts/versioning_system
- Snapshot isolation: https://docs.turingdb.ai/concepts/snapshots
- Regulatory and compliance use cases: https://www.turingdb.ai/use-cases#legal
