Two programs read the same spreadsheet cell. Program A writes a new value. Then program B, which computed its value from the read before A's write, writes to the same cell. Is B's stale write refused, or does A's edit disappear?
| Writer A | Writer B (stale) | What's left in the cell | |
|---|---|---|---|
Google Sheets API (values.update) |
200 | 200 | B's value. A's edit is gone, with no error. |
Excel Online, Microsoft Graph (range PATCH) |
200 | 200 | B's value. A's edit is gone, with no error. |
VisiGrid API (POST …/cells) |
200 | 409 | A's value. B is told to reread. |
This doesn't depend on timing, so it reproduces on every run. Neither Google's
nor Microsoft's cell-write API can express "only if nothing changed since I
read". values.update
has no revision or precondition parameter. Graph's range update
takes no If-Match; Graph's ETags cover only whole-file uploads, not cell edits.
People editing together in the browser are fine in all three products. This is about programs (sync jobs, scripts, AI agents) that read a while ago and write now.
Write-up: https://visigrid.app/blog/spreadsheet-apis-silently-overwrite
Each script uses only curl and jq, and overwrites cell A1 of the first sheet,
so point it at a scratch file.
export GOOGLE_TOKEN=... # access token with https://www.googleapis.com/auth/spreadsheets
export SHEET_ID=... # from the spreadsheet URL: /spreadsheets/d/<SHEET_ID>/edit
bash sheets.shYou can get a token from the OAuth 2.0 Playground
by selecting the Google Sheets API v4 spreadsheets scope. A service account
also works if you share the spreadsheet with it.
export GRAPH_TOKEN=... # access token with Files.ReadWrite
export ITEM_ID=... # drive item id of a scratch .xlsx in your OneDrive
bash excel.sh # WORKSHEET=... if the first sheet isn't Sheet1Graph Explorer gives you
a token (the "Access token" tab). To find the item id, run
GET /me/drive/root:/scratch.xlsx.
export VISIGRID_TOKEN=... # Settings → API tokens on app.visigrid.app
export SHEET_ID=... # from the workbook URL on app.visigrid.app
bash visigrid.shEvery write carries the expected_revision it was computed from. A write from a
revision that's no longer current gets 409 revision_conflict, and nothing is
written.
A and B both read A1: original
A writes 'writer A': HTTP 200
B writes from its stale read: HTTP 200
A1 is now: writer B
=> A's edit was overwritten, and nobody was told
That's Google Sheets. Excel prints the same. VisiGrid prints HTTP 409 on the
fourth line and writer A on the fifth.
bench.mjs produces the other numbers in the write-up: per-call latency, two
minutes of sustained writes from one client, and a 4,000-row recalculation. It
needs Node 20 or later and has no dependencies.
GOOGLE_TOKEN=... SHEET_ID=... VISIGRID_TOKEN=... VISIGRID_SHEET=... node bench.mjsIt adds tabs to SHEET_ID and deletes them at the end. It overwrites the first
sheet of VISIGRID_SHEET, so use an empty workbook. N sets the samples per
test (default 15), SUSTAIN_S the sustained-write duration in seconds (default
120), and ONLY limits the tests (latency,sustained,large).
Excel Online isn't in the benchmark. Microsoft's API terms don't allow performance testing of its services without a written agreement, so for Excel this repository tests only the stale-write behaviour.
Your numbers will differ from ours depending on where you run from. Both services are on the public internet, and Google's quotas depend on your project.
Both APIs rate-limit writes. Google allows 60 write requests a minute per user.
VisiGrid allows 300 writes and 600 reads a minute per token, each write up to
1,000 cells. Over either limit you get a 429; bench.mjs counts those as
refusals and backs off for a second.
MIT