To change a production schema while old and new application versions may be running, use an expand-and-contract migration: add the new structure without removing the old one, migrate application code and data while both shapes are supported, then remove the old structure in a later release. This gives overlapping application versions a compatible schema to use; it does not make every database operation nonblocking or provide high availability by itself.
The example below replaces a published boolean with a status enum. The sequence applies broadly, but the DDL behavior and deployment steps must be checked against your database engine and version, framework, table size, and topology. The cited operational caveats are specific to the documentation named in each section.
As an Amazon Associate I earn from qualifying purchases.
Why a one-step column replacement is risky
If a deployment renames or drops published while old application instances are still running, those instances can issue queries that expect the old column. The same dependency may exist outside the web application—in workers, scheduled jobs, reports, database views, or cached schema metadata. A schema change is safe only when every active consumer can work with the schema it encounters.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Expand and contract separates that incompatible change into three phases. GitLab describes a mixed period in which versions N and N+1 coexist against an expanded schema, and Prisma uses a boolean-to-enum replacement to illustrate the pattern. GitLab’s backwards-compatibility guidance also notes that more complex changes can require multiple milestones.
#1 Best Overall
How to replace a column safely
1. Expand the schema
Add status while keeping published. Choose the new column’s initial nullability, default, constraints, and indexing based on the engine, existing data, and application behavior. At this point, the currently deployed code must continue working unchanged. For a new index, GitLab’s documented staged example adds the index before application code begins to rely on it.
Do not assume that an additive DDL statement is harmless: it may still take locks, wait behind other work, or affect availability depending on the operation, database version, table, and workload. Review the generated SQL and the database documentation for the exact deployed version before running it.
2. Define how the two representations stay consistent
Before changing writes, decide how published maps to status and which representation is authoritative at each point in the rollout. For example, a true boolean might map to published and false to draft, but the correct mapping depends on the product’s domain rules.
- Specify whether application writes update one field or both, and when that policy changes.
- Decide what happens if updating one representation succeeds and updating the other fails. A dual write is not automatically atomic or safe.
- Make a backfill idempotent or resumable where appropriate, so it can be retried without corrupting already-migrated rows.
- Define how to treat records whose values are null, invalid, or inconsistent; do not silently guess a mapping.
3. Backfill existing records
Populate status from existing published values. On a small table, a single operation may be appropriate; on a large or heavily written table, plan the backfill as a separately observable operation with a strategy suited to its size and write rate. Track failures and progress, and establish an explicit completion check. A migration that has started is not necessarily a migration that has finished.
Keep the old field available during the backfill. If writes continue while it runs, the consistency policy must account for records created or changed during that period. Do not switch reads to the new representation until the data needed by those reads has been populated and verified.
4. Migrate application readers and writers
Deploy code that tolerates the transitional schema. The precise sequence depends on the consistency policy: for example, an intermediate release may continue reading the old field while writing both, followed by a release that reads the new field. Keep every version that can coexist during rollout compatible with the expanded schema.
Before proceeding, verify that the rollout and all relevant background work have completed. Include asynchronous workers, scheduled tasks, reporting jobs, and any other known consumers in the check—not only web instances. GitLab’s compatibility guidance describes the overlap of versions N and N+1 on the expanded schema. The exact staged example is specific to its documented application context.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →5. Contract only after dependencies are gone
Remove published in a later contract step, after no running code or other consumer needs it. Check for schema-cache dependencies and database views as well as direct application queries. GitLab’s column-removal guidance discusses these less-visible dependencies and recommends separating the “ignore” and “drop” steps across releases in its documented case. Review that guidance when planning column removal.
Rank #3
Contract work can include more than dropping a column: review dependent indexes, constraints, views, migration transaction boundaries, and any post-deployment migration process. If another change relies on a backfill, require verified completion before that later change or cleanup proceeds.
One-step change or staged migration?
A direct destructive change is shorter, but it assumes old code and other consumers have already stopped depending on the old schema. The staged approach makes compatibility across a mixed-version rollout an explicit design requirement. Neither approach determines whether the underlying DDL is fast or nonblocking.
| Decision axis | One-step destructive change | Expand and contract |
|---|---|---|
| Old code during rollout | Unsafe if any live consumer still expects the old shape. | Can support overlapping versions when the expanded schema and transitional code are compatible. |
| DDL locks or rewrites | Depends on the specific operation, engine, and version. | Still depends on the specific operation, engine, and version; staging does not remove that risk. |
| Data migration | May combine schema and data changes into one risky transition. | Allows a separately managed backfill, with a completion gate before cutover or cleanup. |
| Rollback after new writes begin | May be difficult if the old representation or data is already gone. | May still require reverse synchronization or a forward fix if data has been written only to the new representation. |
| Deployment ordering | Requires the change to align with all application and worker versions. | Requires deliberate expand, migrate, and contract ordering across application versions and background work. |
| Operational checks | Must establish that consumers are compatible and the DDL is safe to run. | Must additionally observe backfill progress, rollout completion, and the gate that permits contract cleanup. |
Compatibility risk is separate from database execution risk
Expand and contract addresses application compatibility: it reduces the chance that old and new code encounter a schema shape one of them cannot use. It does not guarantee that a schema operation will finish quickly, avoid blocking, or succeed without intervention. Table size, lock acquisition, transaction scope, statement and lock timeouts, and engine/version behavior remain operational concerns.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →PostgreSQL with GitLab’s Rails migration framework
GitLab’s migration style guide documents that CREATE INDEX CONCURRENTLY must run outside an explicit transaction. It also covers statement and lock timeouts and the importance of keeping transactions short. Those are GitLab framework-specific migration rules and guidance; check the actual SQL, framework configuration, and PostgreSQL version in your own deployment rather than assuming the same transaction behavior. See GitLab’s migration style guide.
Django migrations across database backends
Django’s migration documentation describes backend differences that affect recovery and availability. MySQL schema alterations are not wrapped in transactions, so a failed migration can require manual repair; newer DDL improvements do not eliminate all locks or interruptions. SQLite may emulate a schema change by creating a replacement table, copying rows, dropping the original, and renaming the replacement, which can be slow. These are documented backend caveats, not a substitute for checking the versions and migration behavior in your deployment. Consult Django’s migration documentation for the applicable backend.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Plan rollback and recovery by phase
Before application writes depend on the expanded representation, rolling back application code may be relatively straightforward if the old schema remains intact. Once writes have gone only to the new representation, an older application may see stale or missing values unless you have a reverse-synchronization plan. Decide whether recovery means restoring dual writes, running a compensating backfill, or deploying a forward fix.
Do not treat a reversible schema migration as proof that the data change is reversible. A column operation may be reversible while transformed, discarded, or newly written data is not. Record the rollback boundary for each release and identify what evidence—such as backfill completion and consumer inventory—must be available before advancing.
Zero downtime also depends on deployment architecture
“Zero downtime” is an outcome under specific infrastructure and sequencing conditions, not a property conferred by the migration pattern. The pattern does not itself provide load balancing, redundancy, or high availability. GitLab’s multi-node zero-downtime upgrade procedure requires load balancing and appropriate HA mechanisms; components without HA may require a separate upgrade with downtime. Its procedure also calls for upgrading one minor release at a time and waiting for required background migrations to complete. Those are GitLab-specific requirements, not universal rules for every application or hosting provider. See GitLab’s multi-node upgrade procedure for its stated prerequisites.
GitLab’s documentation says, “One way to guarantee zero-downtime updates for on-premise instances is following the expand and contract pattern.” Read that statement in context: its compatibility guidance describes the staged phases, while its separate upgrade procedure sets infrastructure and version-sequencing prerequisites. The compatibility guidance and the upgrade procedure together make clear that schema sequencing is only one part of a zero-downtime deployment.
Quick Recap
Production readiness checklist
- Document the old-to-new data mapping and the source of truth at each phase.
- Verify the expanded schema remains compatible with currently deployed application and worker versions.
- Review engine- and version-specific DDL behavior, transaction scope, locks, timeouts, and table-size implications.
- Choose a backfill strategy suited to the table’s size and write rate, and define how to monitor, retry, and verify it.
- Inventory web processes, workers, scheduled jobs, reports, views, and schema caches that may use the old field.
- Gate read cutover on valid migrated data; gate contract cleanup on completed rollout and confirmed removal of old consumers.
- Specify rollback and recovery options for the point at which writes begin relying on the new representation.
- Confirm the deployment topology and upgrade sequence can maintain service availability independently of the schema migration.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




