{
  "id": 12801876,
  "title": "Zero-Downtime Schema Changes in PostgreSQL: Adding Columns and Indexes to a 200M-Row Table",
  "url": "https://urgent.news/2026/10/08/zero-downtime-schema-changes-in-postgresql-adding-columns-and-indexes",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-08T06:05:46.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/musamuhammad/zero-downtime-schema-changes-in-postgresql-adding-columns-and-indexes-to-a-200m-row-table-36b"
  },
  "original_language": "en",
  "account": "This article explains how to perform schema changes on a massive PostgreSQL table with 200 million rows without causing downtime. The key issue is that every DDL statement (CREATE, ALTER, DROP, TRUNCATE) locks the table, which can bring live traffic to a grinding halt.\n\nTo add a column, the safest approach is to add a nullable column with no default value, which only changes the catalog metadata and finishes in milliseconds. For columns with a default value, PostgreSQL 11 and later can add the column with a default instantly. However, adding a NOT NULL column directly is not recommended; instead, do it in steps: add a nullable column first, write the default value from your application, backfill old rows in batches, add a CHECK constraint without scanning the entire table, validate the constraint, set the column to NOT NULL, and finally drop the redundant CHECK constraint. When backfilling old rows, update in small batches instead of a single massive UPDATE to avoid a huge transaction, bloat, replication lag, and dead tuples.\n\nAdding an index the wrong way is to use CREATE INDEX, which takes a SHARE lock and blocks all writes for the entire operation, potentially causing hours of downtime on a table of this size. The correct way is to use CREATE INDEX CONCURRENTLY, which scans the table twice and picks up changes made in between without blocking writes. Running it off-peak and cleaning up invalid indexes is essential.",
  "summary": "You have a PostgreSQL table with 200 million rows . It's serving live traffic. Now you need to add a column or an index. Run the wrong command and every INSERT , UPDATE , and DELETE hangs until it finishes. On a table this size, that can be hours. Here is how to do it safely. The core problem: locks Every DDL statement ( CREATE , ALTER , DROP , TRUNCATE ) takes a lock on the table. What matters…",
  "key_points": [
    "Add nullable column with no default value to change catalog metadata",
    "Backfill old rows in batches for NOT NULL columns",
    "Use CREATE INDEX CONCURRENTLY to avoid table-level locks"
  ],
  "editors_take": "Performing schema changes on a massive PostgreSQL table without downtime requires careful planning, but can be achieved by using specific commands and techniques to avoid locking the table.",
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}