Every source behind this page, graded. Built from repository artefacts:
this session's network reaches code hosts but not blog, paper or talk hosts, so those
tiers are absent by constraint, not by judgement; the ledger in sources.md records the
policy.
Postmortem
GitLab2021-05
The WebHook recent_failures counter may overflow (#330817)
A production incident on GitLab.com: an unbounded increment walked a smallint to
32,768 and WebHookWorkers started throwing. Links the internal incident
(gl-infra/production#4589) and shows the exact offending line.
Carry forwardEvery counter column is an exhaustion clock; bound it in code or the type bounds it for you.
gitlab.com/gitlab-org/gitlab/-/issues/330817
Postmortem
GitLab2020-07
Duplicate key on index_issues_on_project_id_and_iid (#229614)
Recurring production exceptions: imports and live issue creation both computed the
next per-project iid and collided. The thread walks through routing all allocation
through one InternalId mechanism or reserving blocks up front.
Carry forwardOne allocator per ID space; a second "compute the next one" code path is a latent collision.
gitlab.com/gitlab-org/gitlab/-/issues/229614
Postmortem
Nextcloud ecosystem2026-08
fileid numeric value out of range (files_antivirus #697)
An operator's production report: oc_filecache.fileid outgrew an app table's
int(10) unsigned copy of it, and file processing failed with SQLSTATE 22003. The core
widened years earlier; the plugin's column lagged.
Carry forwardExhaustion propagates along foreign keys and plugin schemas; audit the ID's whole reference graph.
github.com/nextcloud/files_antivirus/issues/697
Postmortem
Collection (Basecamp, GitHub, Strava)2014–2021
danluu/post-mortems: the exhaustion entries
The curated postmortem index records three ID-exhaustion outages: Basecamp November
2018 ("a database hit the integer limit, leaving the service in read-only mode"),
GitHub May 2021 (scoped-tokens foreign key at max INT32, "9h48m"), Strava July 2014
(signed-int primary key, uploads failed). The primary write-ups sit on hosts this
session's network cannot reach; claims here are the collection's entries.
Carry forwardExhaustion is a recurring, named, multi-company outage class, not a theoretical risk.
raw.githubusercontent.com/danluu/post-mortems/master/README.md
Decision record
GitLab2020-04
Tracking primary key integer overflow risk for ci_builds.id (#215017)
The near-miss, recorded in public: the largest CI table measured at 1.168bn IDs
(54.42% of int4) in April 2021, with exhaustion forecast between September 2021 and May
2022 depending on the growth model.
Carry forwardForecast exhaustion per table with two growth models and plan against the pessimistic one.
gitlab.com/gitlab-org/gitlab/-/issues/215017
Source
GitLab2020-12
Migration helpers for int to bigint conversion (!49778)
The online widening machinery: shadow bigint column, trigger keeping both in sync,
batched background backfill, then the swap; explicitly "DOWNTIME = false", covering the
primary key and every referencing foreign key.
Carry forwardOnline widening is a dual-write system on your own primary key; budget it as a programme, not a migration.
gitlab.com/gitlab-org/gitlab/-/merge_requests/49778
Source
GitLab2024-06
Cleanup migration failure for p_ci_builds bigint conversion (#468671)
The long tail: a cleanup migration from the bigint programme raising
PG::DependentObjectsStillExist in an upgrade test environment, three and a half years
after the helpers merged.
Carry forwardThe conversion is not done when the column swaps; the cleanup phase can still break upgrades years later.
gitlab.com/gitlab-org/gitlab/-/work_items/468671
Source
GitLabliving doc
Patroni runbook: duplicate key log analysis
The operator's view of duplicate issuance: unique-violation storms explained as a
sequence that "has been modified (i.e. has been RESET)", remediated with setval() above
the true maximum or absorbed with ON CONFLICT.
Carry forwardAfter any failover, verify sequences against max(id) before declaring the database healthy.
gitlab.com/gitlab-com/runbooks: patroni/log_analysis.md
Source
Nextcloud2019-01
Columns missing conversion to big int (server #13704)
Why widening ships as an opt-in command: "changing column types on big tables could
take some time", so upgrades skip it and admins run
occ db:convert-filecache-bigint offline.
Carry forwardIf you ship software others operate, the widening you defer becomes thousands of other people's maintenance windows.
github.com/nextcloud/server/issues/13704
Vendor
Nextcloudchecked 2026-09
Admin manual: bigint identifiers
The official cost statement: conversion "can take several hours or even days,
depending on the number of files", with the web server down or maintenance mode on.
Carry forward"Hours or days, offline" is the price of the narrow default, stated by the people who charge it.
nextcloud/documentation: bigint_identifiers.rst
Source
Twitter2010
Snowflake README (snowflake-2010 branch)
The founding document of the node-local family: 10k IDs/s/process under 2 ms,
uncoordinated, k-sorted within about a second, 64 bits; and the clock posture, refusing
to mint until time passes the last issued ID.
Carry forwardDecide the backwards-clock behaviour (refuse vs counter) before the first deploy; it is the generator's availability contract.
github.com/twitter-archive/snowflake
Source
Sony2015
Sonyflake README
The same 64 bits, re-budgeted: 39 bits of 10 ms ticks (174 years), 16 bits of
machine (65,536 nodes), 8 bits of sequence (256 per 10 ms). A worked example of the
bit-budget trade.
Carry forwardLifetime, node count and mint rate trade against each other inside 64 bits; write your numbers down before picking a layout.
github.com/sony/sonyflake
Source
Segment (Twilio)2017
KSUID README
Time-ordered without coordination: 32-bit timestamp plus 128 random bits, "64 times
larger than the 122 bits" of UUIDv4; 20 bytes binary, 27 characters of base62 that sort
correctly as text.
Carry forwardBuying out of worker-ID assignment costs about 12 extra bytes per key, everywhere the key appears.
github.com/segmentio/ksuid
Source
ULID project2016
ulid/spec
The spec that names UUIDv4's problem ("can cause fragmentation in many data
structures") and defines same-millisecond monotonicity by incrementing the random
component, with generation failing on overflow.
Carry forwardRead the monotonicity clause of any ID spec for its overflow behaviour; that is where the guarantees end.
github.com/ulid/spec
Decision record
Mastodon2017-10
Non-serial ("snowflake") IDs (PR #4801)
A complete recorded argument: motivation ("purely to hide the total number of
entries in each table"), dissent ("no perceivable benefit to >90% of instances"),
scope cut to statuses, IDs returned as strings to protect JavaScript's 53-bit integer
precision.
Carry forwardSequential public IDs publish your growth curve; and any 64-bit ID that reaches a browser must travel as a string.
github.com/mastodon/mastodon/pull/4801
Decision record
IETF uuidrev WG2024-05
rfc4122bis working repository
The UUID revision drafted in public on GitHub and published as RFC 9562 in May 2024,
obsoleting RFC 4122 after 19 years.
Carry forwardThe standard now includes what production converged on; new systems no longer need a bespoke scheme to get sortable IDs.
github.com/ietf-wg-uuidrev/rfc4122bis
Decision record
IETF uuidrev WG2024
RFC 9562 text: locality, monotonicity, security, background
Four load-bearing statements: the order-of-magnitude locality claim for time-ordered
keys; three standardised monotonicity methods; "MUST NOT be used as security
capabilities"; and a background cataloguing ~16 non-standard schemes the industry built
first.
Carry forwardThe RFC is the decision record for the whole field: read its background section as a map of what everyone tried.
rfc4122bis: draft-ietf-uuidrev-rfc4122bis.md
Source
PostgreSQL2024-12
commit 78c5e141: Add UUID version 7 generation function
uuidv7() lands with RFC method 3: a 12-bit sub-millisecond fraction in rand_a,
keeping generation monotonic within a backend "even when the system clock goes
backward."
Carry forwardA database-resident generator can absorb clock steps a node-resident one must refuse; that is a real availability difference.
github.com/postgres/postgres/commit/78c5e141...
Source
2ndQuadrant / Tomas Vondra2018
tvondra/sequential-uuids
The clearest statement of the random-key problem: uniform distribution means "all
index leaf pages are equally likely to be hit, forcing the whole index into memory";
plus two wrap-around generator designs that bound the damage without going fully
sequential.
Carry forwardThe pain threshold is the index outgrowing shared buffers; below it random keys are fine, above it they thrash.
github.com/tvondra/sequential-uuids
Source
Rails2016-12
PR #26266: Change default primary keys to BIGINT
The systemic fix, merged: new Rails tables get 64-bit keys, with a migration
compatibility layer so old migrations keep producing int and old schemas stay
loadable.
Carry forwardExhaustion is best fixed in the defaults, one framework level above the application that will forget.
github.com/rails/rails/pull/26266
Source
Rails2016 (closed unmerged)
PR #24962: bigserial by default (the rejected first attempt)
Closed without merge after core maintainers showed the same migration would produce
different schemas on Rails 4 and 5 and schema dumps would drift; superseded by #26266,
which added the versioned compatibility layer.
Carry forwardChanging an ID default is an ecosystem migration; the mechanism that versions old behaviour is most of the work.
github.com/rails/rails/pull/24962
Decision record
CockroachDB2022-03
Issue #78049: use hash-sharded indexes by default
The range-sharded world's view of ordered keys, argued by a founder: sequential keys
cause "major performance problems", the fix exists but is not the default, and the cost
of the fix is scan performance "proportional to the number of buckets". Still open.
Carry forwardOn range-partitioned stores, treat any monotonic key (including UUIDv7) as a write hotspot until proven otherwise.
github.com/cockroachdb/cockroach/issues/78049
Source
CockroachDB2019-08
Issue #39340: improve UX for hash-sharded indexes
The design argument that produced the USING HASH syntax: an index on a timestamp
column "would have a hot spot", the manual workaround (computed hash column plus check
constraint) "is starting to get heavy", so the database should "shoulder the burden of
hashing" behind new syntax.
Carry forwardIf avoiding ordered-key hotspots takes manual schema gymnastics, teams will not do it; the store has to make the safe shape cheap.
github.com/cockroachdb/cockroach/issues/39340
Source
stateless-me2025
uuidv47
Both halves of the tension at once: "store sortable UUIDv7 in your database while
emitting a UUIDv4-looking façade at your API boundary", by XOR-masking only the
timestamp field with a keyed SipHash-2-4 stream.
Carry forwardIndex order and external opacity are separable; you can keep the fast key inside and show strangers noise.
github.com/stateless-me/uuidv47