Every source behind this page, graded and filterable. All of them are
GitLab's own primary record; the reason for that, and what it costs the guide, is stated
below the wall.
Postmortem
GitLab2016-07
Postgres DB Split brain incident led to data loss
The earliest detailed postmortem in the tracker. Two databases both took writes for six
hours after an unalerted Pacemaker failover, and the losing node's writes were discarded
deliberately to restore a single primary.
Carry forwardAlert on the failover event itself, not only on
the symptoms it is supposed to prevent.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/48
Postmortem
GitLab2017-02
Hourly LVM snapshots of the production databases
One of a cluster of issues filed on 1 February 2017, the day after a database incident.
It states that the existing 24-hour snapshot has proven to be inadequate as a recovery
technique
, which dates the moment GitLab's backup posture changed.
Carry forwardRecovery point objectives are discovered during
recovery, not during design. Test the restore, not the backup.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/113
Postmortem
GitLab2017-02
Update PS1 across all hosts to differentiate hosts and environments
Filed alongside the snapshot issues. The corrective action is a shell prompt: show the
environment in colour and show more of the hostname, so an engineer on a console knows
which machine they are on.
Carry forwardSome of the highest-value corrective actions are
interface changes for humans under stress, and they are the first to be dismissed as
trivial in a design review.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/111
Case study
GitLab2018-07
GCP Migration: short maintenance window to test fixes from the dry run
The 2018 move off Azure was rehearsed with announced maintenance windows. The test plan
reads as a list of things that went wrong in the first dry run, including closing and
reopening the front door correctly and verifying that it closed.
Carry forwardThe rehearsal artefact is more useful than the
migration announcement: it names what the team did not trust.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/366
Postmortem
GitLab2018-08
No automated wal-e database backups in gprd
Three days after the migration, automated base backups were absent in the new
environment and nothing alerted. Found by an engineer who happened to look at the restore
host.
Carry forwardEvery corrective action needs an alert that fires
when the corrective action stops existing.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/414
Postmortem
GitLab2021-05
Long-running CREATE INDEX blocking vacuum
A near miss recorded in plain language: twelve hours from a full database shutdown
because an index build had been running for five and a half hours and vacuum could not
proceed.
Carry forwardTransaction ID wraparound is a capacity limit
with a deadline, and large tables are how you reach it accidentally.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/4633
Postmortem
GitLab2023-07
Site-wide outage triggered by restart of stale terraform pipeline
231 minutes of 503s, root-caused to a configuration change. Its labels are as
informative as its body: blocks deployments and
blocks feature-flags, the two levers an incident response needs most.
Carry forwardA stale pipeline is a loaded change waiting for
someone to press restart. Expire them, or make restart require re-planning.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/15997
Postmortem
GitLab2026-02
Incident review: Redis deployment error, CI delays and Duo outage
The clearest single document in the corpus. It contains the PDB and NEG disagreement,
the measured blast radius, and the sentence about the revert that could not be merged
because the pipelines were down.
Carry forwardList the emergency actions that depend on the
system you would be fixing, and give at least one of them a path that does not.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/21208
Postmortem
GitLab2026-05
Error rates violating SLO (Redis Sidekiq memory exhaustion)
A severity 1 in which the stated cause is an earlier incident's mitigation: deferred
audit event jobs accumulated until Redis memory was exhausted and the cluster lost
quorum, with a backlog above 12 million jobs.
Carry forwardWrite the expiry condition into every mitigation
at the moment you apply it, because the mitigation is now a component.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/22103
Postmortem
GitLab2026-05
Incident review: Redis primary CPU saturation approaching capacity limit
A near-repeat one week after the severity 1, with the same worker and the same shard,
because the corrective actions had not yet shipped. It also identifies the feedback loop:
deferring the job made Sidekiq itself the dominant source of new enqueues.
Carry forwardThe window between an incident and its corrective
action is a known-vulnerable period; treat it as an active risk with an owner, not as
project backlog.
https://gitlab.com/gitlab-com/gl-infra/production/-/issues/22170
Decision record
GitLab2021-06
Limit on-disk table size to under 100 GB for GitLab.com
The pivot document of the decade. It sets a numeric target, lists the top 30 tables with
sizes, ties specific incidents to specific tables, and spawns two ADRs that turn the
target into a static-analysis rule.
Carry forwardTurn the scaling limit you discovered into a lint
rule in the codebase. Guidance decays; a failing pipeline does not.
https://gitlab.com/gitlab-com/content-sites/handbook/.../database_size_limits
Decision record
GitLab2021-01
CI/CD Scaling
Records the integer primary-key ceiling on ci_builds as an existential
deadline for December 2021, the two options considered for build queuing, and the
decision to move serialised columns to a metadata table to slow growth.
Carry forwardAudit your oldest tables for the framework
defaults they were created with. The default that was fine in 2012 is the outage in 2021.
https://gitlab.com/gitlab-com/content-sites/handbook/.../ci_scale
Decision record
GitLab2026-09
Cells design document (Protocells)
The fourth iteration of the cell architecture, narrowed to one goal: reducing load on
the legacy cell's database. Carries a decision log of 28 ADRs, one marked obsolete, and a
future-scope section listing what the earlier iterations promised and this one defers.
Carry forwardA multi-year platform programme becomes
deliverable when its goal gets smaller. Write down which of the original promises you are
deferring, and where.
https://gitlab.com/gitlab-com/content-sites/handbook/.../cells
Decision record
GitLab2026-09
Cells: goals, glossary and requirements
Requirements written as a prioritised table, including 10x headroom at high priority and
100x at medium, and cost per user similar or lower to GitLab.com
as an explicit
constraint on the design.
Carry forwardGive headroom a number and a priority in the
requirements, so the architecture can be argued against evidence rather than taste.
https://gitlab.com/gitlab-com/content-sites/handbook/.../cells/goals.md
Decision record
GitLab2026-09
Cells ADR 001: routing technology using Cloudflare Workers
A complete ADR: two proofs of concept, one chosen, the alternatives named, and the
consequences accepted in writing including increased vendor lock-in and a requirement
knowingly unmet.
Carry forwardName the requirement your chosen option fails and
its priority. That single line is what makes an ADR auditable two years later.
https://gitlab.com/gitlab-com/content-sites/handbook/.../001_routing_technology.md
Decision record
GitLab2026-09
Rejected: stateless router using request buffering
A full design kept after rejection, with the reason preserved: cells bounce requests
they cannot serve, which requires buffering and allows a request to be processed more
than once.
Carry forwardKeep the rejected design in the repository next to
the accepted one. It is the cheapest institutional memory available.
https://gitlab.com/gitlab-com/content-sites/handbook/.../rejected/buffering-requests
Decision record
GitLab2026-09
Transaction management in Gitaly (status: rejected)
A design that was implemented and is now being deleted. The header explains that
rejected is the closest available status and that the work was largely
built and is now being unwound
, along with the features that depended on it.
Carry forwardGive your design document a status field that can
express "built and withdrawn". Most templates cannot, which is why most organisations
lose this information.
https://gitlab.com/gitlab-com/content-sites/handbook/.../gitaly_transaction_management
Decision record
GitLab2026-06
Scaling Git (proposal)
The third attempt at horizontal Git scaling, and the document that declares the second
one failed. Proposes object storage as the source of truth with stateless Gitaly nodes
and a content-addressed MVCC format, and names agentic workloads as a rising load source.
Carry forwardIf two attempts to replicate state have failed,
the next move is usually to stop replicating and start sharing. The cost is latency;
the gain is that any node can serve anything.
https://gitlab.com/gitlab-com/content-sites/handbook/.../scaling-git
Decision record
GitLab2024-11
Siphon: CDC from PostgreSQL to a queue
Moves analytical consumers off the transactional database by streaming logical
replication events into a pub/sub layer, with an explicit non-goal of letting the
application emit custom events.
Carry forwardForbidding custom events keeps the change stream
honest: every event has a row behind it, so the stream cannot drift from the database.
https://gitlab.com/gitlab-com/content-sites/handbook/.../siphon
Decision record
GitLab2022-12
Use Zoekt for code search
Keeps Elasticsearch for issues and comments and adds a purpose-built engine for code,
on the grounds that code search needs exactness and regex support that the general engine
does not provide.
Carry forwardOne search engine for two query models is a
false economy. Split by query semantics, not by data type.
https://gitlab.com/gitlab-com/content-sites/handbook/.../code_search_with_zoekt
Decision record
GitLab2026-09
Rails monolith decomposition
Proposed in 2023 and still proposed in 2026, now with a section headed "the agentic
imperative" arguing that modular boundaries are a prerequisite for agents, which cannot
carry the implicit context a long-tenured engineer carries.
Carry forwardWatch for the rationale under a long-lived
proposal changing. It tells you which argument the organisation now finds persuasive.
https://gitlab.com/gitlab-com/content-sites/handbook/.../modular_monolith
Source
GitLab2021-06
Draft: add Database Sharding blueprint (closed, never merged)
The sharding design of 2021, opened as a draft merge request and closed unmerged. The
approach that eventually shipped instead is domain decomposition followed by the Cells
programme.
Carry forwardA closed, unmerged design MR is a dated record of
a direction not taken. Search for them before you propose the same thing.
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64115
Source
GitLab2026-08
Remove Raft, WAL and transaction code (epic 23151)
The removal programme for the Gitaly transactional cluster, with the order of work and
the reason: the code is dead weight: a large surface to maintain
. One constituent
merge request touches 365 files.
Carry forwardBudget the removal when you budget the build. The
cost of unwinding a partially adopted architecture is measured in review capacity, not in
engineering days.
https://gitlab.com/groups/gitlab-org/-/epics/23151
Source
GitLab2026-09
Gitaly design document
The original argument for putting an RPC layer in front of Git, with the measurement
that motivated it and the alternative that was refused. Still in the repository ten years
later, now describing a system whose storage model is being replaced.
Carry forwardWhen latency is two orders of magnitude above CPU
time, the answer is in the storage path, and no amount of application tuning will find
it.
https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/DESIGN.md
Source
GitLab2026-09
Multiple databases (development documentation)
Documents the live decomposition into main, ci and
sec, and the application-level gitlab_schema classification
that enforces it, including why PostgreSQL schemas were not used.
Carry forwardIf the database cannot enforce the boundary
cheaply, enforce it in the application and make the classification mandatory per table.
https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/database/multiple_databases.md
Source
GitLab2026-09
GitLab.com metrics catalogue
117 service definitions in jsonnet, which is the most precise public statement of
GitLab.com's topology: every Redis family, every PostgreSQL cluster, the topology
service, Zoekt, Siphon and ClickHouse all appear as first-class services.
Carry forwardA monitoring catalogue in version control is an
architecture diagram that cannot go stale, because an unmonitored service is an outage.
https://gitlab.com/gitlab-com/runbooks/-/tree/master/metrics-catalog/services
Source
GitLab2026-09
Sidekiq sharding runbook
The operational procedure for adding a Redis shard and moving workers onto it, including
why Redis Cluster was not used and the recommendation of one queue per shard.
Carry forwardHot-key distribution decides whether clustering
helps. Measure the key distribution before choosing a sharding technology.
https://gitlab.com/gitlab-com/runbooks/-/blob/master/docs/sidekiq/sharding.md
Case study
GitLab2026-09
Capacity planning for GitLab infrastructure
Describes classifying every monitored resource by whether it scales horizontally,
forecasting saturation daily with Prophet through a tool called Tamland, and filing the
warnings as issues on a public board.
Carry forwardClassify resources as horizontally scalable or
not, and let that classification set the priority of the warning. It is the cheapest way
to stop treating every saturation alert as equally urgent.
https://gitlab.com/gitlab-com/content-sites/handbook/.../capacity-planning.md
Case study
GitLab2026-09
Production architecture (controlled document)
The audited description of what runs GitLab.com: Google Cloud us-east1,
four production Kubernetes clusters, and datastores deliberately outside them.
Carry forwardWrite down which components are exempt from your
platform standard and why. The exemption list is where the operational risk lives.
https://gitlab.com/gitlab-com/content-sites/handbook/.../production/architecture
Case study
GitLab2026-09
Deployments and releases
Establishes the cadence that the database size target was protecting: changes deploy to
GitLab.com multiple times per day from packages built off the default branch, and
self-managed packages follow monthly.
Carry forwardState your deployment cadence as a constraint in
database design reviews. It is the number that decides whether a migration is acceptable.
https://gitlab.com/gitlab-com/content-sites/handbook/.../deployments-and-releases