Email me

Explainer · 9 min read

Filed under App development

Lamport clock vs vector clock: what each one can actually prove

Short answer

A Lamport clock is one counter per machine. If event A caused event B, A gets the smaller number, but the reverse is not true: a smaller number does not prove anything. A vector clock keeps one counter per machine, so comparing two vectors tells you whether one event really came first or whether they were concurrent (neither could have affected the other). In our simulation of 100 nodes, only 5.3% of the pairs a Lamport clock put in order were actually cause and effect.

Bar chart titled Lamport says A came first, how often is that real. Share of Lamport-ordered event pairs that are truly causal, 2,000 events per run, mean of 5 runs: 2 nodes 99.0%, 3 nodes 97.9%, 5 nodes 94.3%, 10 nodes 84.7%, 20 nodes 66.2%, 50 nodes 26.3%, 100 nodes 5.3%.
When a Lamport clock puts event A before event B, how often A really could have affected B. The answer collapses as nodes are added. Our simulation, Oct 25 2026, 35 runs, all in the data file on this page. Chart by Tensorust from our own simulation.

Part of the article Pick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%. This page answers one question from it in depth.

On this page · 12 sections
  1. Key numbers
  2. The problem both clocks solve
  3. How a Lamport clock works
  4. How a vector clock works
  5. What we found when we ran both
  6. The price of knowing: vector size
  7. Where this shows up in your IDs
  8. Common misconceptions
  9. What this means for you
  10. Related
  11. FAQ
  12. Sources

Every database vendor sells you "ordering". Google bought GPS receivers and atomic clocks to get it. The 1978 math underneath costs nothing, and it is worth knowing what it can and cannot prove before you pay for more.

Key numbers

What Number Source (checked Oct 25 2026)
Lamport's paper Communications of the ACM 21(7), July 1978, pages 558 to 565 Lamport's publication list
Lamport-ordered pairs that were truly causal, 2 / 10 / 100 nodes 99.0% / 84.7% / 5.3% our simulation, data.csv on this page
Concurrent pairs a Lamport clock still put in strict order 95.5% to 98.1% our simulation
Size per timestamp, Lamport vs vector clock at 100 nodes 8 bytes vs 800 bytes 8-byte counters, our arithmetic
Our PC's clock vs 5 public time servers 1,010 to 1,014 ms behind our SNTP queries, Oct 25 2026 8:12 PM ET
Spanner TrueTime uncertainty about 1 to 7 ms, 4 ms most of the time Spanner paper, OSDI 2012
CockroachDB default max clock offset 500 ms, then nodes shut down CockroachDB docs
Dynamo shopping cart reads that saw exactly one version 99.94% Dynamo paper, SOSP 2007

The problem both clocks solve

Two servers write to the same record. Which write came first? You cannot just compare their wall clocks, because their clocks disagree. We checked ours while writing this: our Windows 11 PC was a full second behind every public time server we asked, because its Windows Time service was not running.

Horizontal bar chart titled Our PC clock was a full second behind. Median offset of NTP server time minus our clock on October 25 2026: time.nist.gov 1,014 ms, time.google.com 1,012 ms, time.windows.com 1,012 ms, time.cloudflare.com 1,010 ms, pool.ntp.org 1,010 ms. 21 raw SNTP queries from our PC to 5 public time servers, Oct 25 2026, 8:12 PM ET. Round trips were 6.5 to 58 ms, so the error is the clock, not the network.

A one-second gap means any reply our PC sends within a second of receiving a message is stamped earlier than the message it answers. Sort by timestamp and the answer shows up before the question. That is the bug Leslie Lamport fixed on paper in 1978, without touching a physical clock.

How a Lamport clock works

Lamport's rules, from Time, Clocks, and the Ordering of Events in a Distributed System:

  1. Each process keeps one integer counter and adds 1 before every event.
  2. Every message carries the sender's counter.
  3. On receipt, the receiver sets its counter to the larger of its own and the message's, plus 1.

That guarantees what Lamport called the Clock Condition: if a happened before b, then C(a) is less than C(b). Break ties by process ID and you get a total order of every event in the system, which is enough for mutual exclusion, replicated logs and leader election. Lamport himself calls it "my most often cited paper" and adds, dryly, that "many computer scientists claim to have read it."

What you do not get is the converse. C(a) less than C(b) does not mean a caused b. Two events on machines that never talked still get different numbers, and the clock cannot tell you so.

How a vector clock works

A vector clock, worked out independently by Colin Fidge and by Friedemann Mattern, keeps one counter for every process:

  1. Process i adds 1 to its own slot before each event.
  2. Every message carries the whole vector.
  3. On receipt, take the larger value in every slot, then add 1 to your own.

To compare two events, compare the vectors slot by slot. If every slot of A is less than or equal to B's, A happened before B. If B is ahead in one slot and A in another, they are concurrent: neither could have caused the other. That one extra answer is the whole point.

Space-time diagram of three servers. Server A has event a with Lamport time 1 and vector 1,0,0, which sends to Server B, and later event b with Lamport time 2 and vector 2,0,0. Server B has c at 1 and 0,1,0, d receiving a at 2 and 1,2,0, and e at 3 and 1,3,0, which sends to Server C. Server C has f at 1 and 0,0,1 and g receiving e at 4 and 1,3,2. Lamport says b came before e; the vectors 2,0,0 and 1,3,0 show they are concurrent. Three servers, seven events. Lamport puts b (2) before e (3). The vectors show they are concurrent: neither server knew about the other's event. Diagram by Tensorust.

What we found when we ran both

We simulated 2,000 events spread across 2 to 100 processes, 5 runs at each size (35 runs, about 2 million event pairs each). Each step, a random process either received a waiting message or did a local event, and 35% of those local events also sent a message to a random peer. We tagged every event with both clocks, then used the vectors as ground truth.

  • With 2 nodes, 1.0% of pairs were concurrent and a Lamport order was causal 99.0% of the time. Lamport is basically right.
  • With 10 nodes, 15.6% of pairs were concurrent and the Lamport order was causal 84.7% of the time.
  • With 100 nodes, 94.9% of pairs were concurrent and the Lamport order was causal just 5.3% of the time.
  • At every size, the Lamport clock still put a strict order on 95.5% to 98.1% of the concurrent pairs. It never says "I don't know". It just picks.

Our setup is a model, not your system: fixed total events means each node does less as nodes are added, which pushes concurrency up. But the direction is the lesson. The more independent writers you have, the more a single counter's "before" is a coin you flipped yourself.

The price of knowing: vector size

Vector clocks grow with the number of writers. At 8 bytes per counter, 100 nodes means 800 bytes riding on every version of every record, against 8 bytes for a Lamport time. Real systems pick a side:

  • Amazon Dynamo used vector clocks to keep conflicting shopping cart versions and let the application merge them. Its paper reports that over 24 hours, 99.94% of requests saw exactly one version and 0.00057% saw two.
  • Apache Cassandra went the other way. Its docs say that unlike Dynamo, it "uses a simpler last-write-wins model where every mutation is timestamped". Cheaper, and the later wall-clock time wins a conflict, even when that clock is a second slow like ours.
  • Google Spanner made wall clocks honest instead: TrueTime uses GPS and atomic clocks, keeps uncertainty around 1 to 7 ms, and makes each commit wait out at least twice that uncertainty.
  • Hybrid logical clocks (Kulkarni and colleagues, 2014) take physical time plus a small counter, respect cause and effect like a Lamport clock, stay close to NTP time, and fit in 64 bits. CockroachDB runs on this idea and, per its docs, crashes nodes whose clocks drift past 500 ms by default rather than risk inconsistent reads.

Where this shows up in your IDs

Time-ordered IDs are Lamport's problem in disguise. RFC 9562 calls monotonicity "the backbone of time-based sortable UUIDs", then lets implementations alter the timestamp to keep it. In our UUIDv7 library test, Python's standard library ran 60 minutes ahead of the clock after it stepped back an hour, because it chose order over honest time. A UUIDv7 or a Snowflake ID orders events on one machine well. Across machines, it orders them by whoever's clock is fastest.

Common misconceptions

Myth

"A Lamport timestamp tells you which event caused which."

The recordOnly one direction holds: cause implies a smaller number. A smaller number does not imply cause. In our 100-node runs, 94.7% of Lamport-ordered pairs were not causal at all.

Myth

"Vector clocks give you a total order."

The recordThey give a partial order. Concurrent events stay concurrent, and your code has to decide what to do with them, which is why Dynamo handed conflicting carts back to the application.

Myth

"NTP makes wall clocks good enough."

The recordOnly while it runs. Ours was not running, and the PC drifted a full second with nothing on screen to say so. Spanner pays for GPS and atomic clocks because 1 to 7 ms is the best it could guarantee.

Myth

"Bigger systems just need a bigger clock."

The recordThe gap grows with independent writers, not with traffic. Two nodes stay 99% honest; a hundred do not.

What this means for you

If one database is your single writer, you do not need any of this; let it assign the order. If you run several writers, decide what you need to know. For "roughly in order, cheap", a Lamport clock or a time-ordered ID is fine. For "did these two writes conflict?", you need vectors or a hybrid clock, plus a merge rule. Either way, check your own servers' clock offset today; ours took 30 seconds to measure. Generate and decode time-ordered IDs in the browser with our UUIDv7 tool and Snowflake ID decoder.

FAQ

What is the difference between a Lamport clock and a vector clock?

A Lamport clock is one counter per process. It guarantees that if event a caused event b, a gets a smaller number, but a smaller number does not prove a caused b. A vector clock keeps one counter per process, so comparing two vectors tells you exactly whether one event happened before the other or whether they were concurrent.

Can a Lamport clock detect concurrent events?

No. Two events with Lamport times 2 and 3 might be cause and effect, or might have happened on different machines with no contact at all. In our simulation, Lamport clocks still put a strict order on 95.5% to 98.1% of the pairs that were actually concurrent.

Why not just use the wall clock?

Because machine clocks disagree. Our own Windows PC was 1,010 to 1,014 ms behind five public time servers on October 25, 2026, with its time service stopped. Any reply it sent within a second of receiving a message would carry an earlier wall-clock time than the message it answered.

What is a hybrid logical clock?

A hybrid logical clock, proposed by Kulkarni and colleagues in 2014, pairs the physical time with a small logical counter. It stays close to the wall clock but still respects cause and effect, and it fits in a 64-bit NTP-format timestamp. CockroachDB uses this approach and refuses to run when node clocks drift past 500 ms by default.

Why don't all databases use vector clocks?

They grow with the number of writers: one counter per node or client. At 8 bytes per entry, a 100-node vector is 800 bytes on every version, versus 8 bytes for a Lamport time. Amazon's Dynamo used them and reported that 99.94% of shopping cart reads saw a single version; Cassandra chose last-write-wins timestamps instead.

Sources

All checked October 25, 2026.

Papers

Docs and standards

  • Cockroach Labs, cockroach start: --max-offset, default 500ms, servers crash past it.
  • Apache Cassandra, Dynamo architecture: last-write-wins instead of Dynamo's vector clocks.
  • IETF, RFC 9562, sections 6.1 and 6.2: timestamp altering, monotonicity and counters.

Our data

  • Simulation: 35 runs (2, 3, 5, 10, 20, 50 and 100 processes, 5 seeds each), 2,000 events per run, both clocks on every event, every pair compared, October 25, 2026. Every run is in data.csv on this page.
  • Clock offset: 21 raw SNTP queries from our Windows 11 PC to time.google.com, time.cloudflare.com, time.windows.com, pool.ntp.org and time.nist.gov at 8:12 to 8:13 PM ET, cross-checked with w32tm /stripchart (about +1.01 s against all three servers it reached). w32tm /query reported the Windows Time service was not started.

Images

  • Charts and diagram by Tensorust from the data above.

Next question

Every number on this page links to its source and was checked on Oct 25, 2026. Spot an error or a newer figure? Email matt@tensorust.com and it gets fixed. Related: UUIDv7 generator and decoder, Snowflake ID decoder.

Read next

Back to The Manual →   All articles →

Get the next one by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Up next

The article this answer comes fromPick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%We tested 10 UUIDv7 libraries with 1M IDs each and a clock jump. .NET put 50% out of order, uuid6 ran 16.6 min ahead. The 2 that passed, plus free data.Read it next →

Get the receipts by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Cite this

Free to cite and reuse under CC BY 4.0 with a link back. How it was collected: methods. Spotted an error? Corrections.

Did this answer your question?

Popular in the shop

All 124 tools →

Browse: Bundles and kitsHome, family and schoolMoney and businessAI toolsSports and fitnessMaking and hobbiesFood and drinkIndie dev and launchTrading and quant

Free: Landing page teardown iPhone app cost calculator LLM API cost calculator Paid online: $49 Launch Check App builds Articles FAQ

Disagree, or have a number to add? Discuss this on The Floor →

What are people saying about this? Read and post on The Floor →