The model upgrade went smoothly. The vector index rebuild took eleven days. This is the failure mode schema migration planning misses in LLM systems: teams budget for compute, for API costs, for engineering time to integrate a new embedding model — and they do not budget for the fact that changing embedding dimensions means re-generating every stored vector, rebuilding every index, and recalibrating every downstream similarity threshold. It also shows up when a second LLM provider is added and its response JSON doesn't match the stored schema, when a new classification label requires backfilling thousands of historical records, or when a prompt template changes in production without version-locking and breaks result reproducibility. The migration itself is the critical path, not the model swap.

This article covers the four core migration patterns, the database-specific behaviour that will surprise you, the tools that help, and the LLM-specific challenges that don't appear in standard database migration guides.

The four LLM-specific schema challenges

Standard database migration literature focuses on table restructuring, column type changes, and index maintenance. LLM pipelines add three schema surfaces beyond the relational tables that most guides cover — each with its own migration semantics.

Schema surfaces in an LLM pipeline
Relational DB
Standard territory
Tables, typed columns, foreign keys, indexes. Standard tooling applies. Complexity scales with table size and write concurrency.
Vector Store
Full rebuild required
HNSW / IVF-Flat indexes over fixed-dimensional embedding vectors. Every dimension change invalidates the entire index. Cannot be migrated in-place.
Prompt Store
Versioning-first
Templates, variable schemas, output constraints. Migration is row-level, not DDL — but immutable versioning is the prerequisite for reproducibility and regression testing.
Classification
Design for extension
Label taxonomies, confidence scores, model attribution. Enum columns turn every new category into a DDL change; junction tables make it a row insert.

The four LLM-specific challenges in detail

Full rebuild
Vector dimension changes
Embedding models encode meaning into fixed-dimensional vectors. Dimensions are not interchangeable — even if two models produce the same count, they represent entirely different geometric spaces. Upgrading the embedding model requires re-generating every stored vector from source documents, rebuilding every HNSW or IVF-Flat index, and recalibrating all similarity thresholds. Treat the vector store as atomic: partial migration produces non-comparable results. Some models support Matryoshka Representation Learning (MRL), which allows the same model to produce truncated outputs at lower dimensions — useful for phased migrations.
JSONB
LLM output storage evolution
LLM responses differ by model and version: token counts, confidence fields, tool calls, citation objects, reasoning traces. Storing responses as JSONB in PostgreSQL allows schema-free evolution — new fields appear in future records without breaking queries on old ones. However, JSONB parses at insert time and stores a binary tree with sorted keys; columns that become hot paths in queries should eventually be extracted to typed columns for index efficiency. The expand-then-extract pattern applies: start with JSONB flexibility, extract to columns once the schema stabilises.
Immutable records
Prompt versioning
Prompt templates are code. When a prompt changes, the outputs change — often in ways that make old and new results non-comparable. Production systems need a prompt schema that captures: template version ID, variable schema (expected input fields), tool definitions, structured output schema, and deployment status (staging / prod / rolled-back). Prompts should be stored as immutable records with version IDs, not overwritten. This is the prerequisite for any meaningful A/B testing, audit trail, or regression investigation.
Junction tables
Classification label evolution
Classification taxonomies change. Adding a new label class is straightforward in application code but creates a schema problem in the database: existing records have no value for the new label, old models cannot produce it, and retraining on historical data requires a labelling strategy. Storing classifications in junction tables or JSONB arrays — rather than enum columns — allows new label values to be added without altering the base table schema. Backfilling existing records with a programmatic labeller avoids the cold-start problem (arXiv:2501.12332).

The four core migration patterns

There are four patterns that cover the vast majority of production schema changes. They differ primarily in how much downtime they require and how complex rollback becomes if something goes wrong.

Expand-Contract
Zero downtime · Reversible
Three phases: expand the schema (add new column or table while keeping old), transition (dual-write to both, backfill historical data), contract (remove old structure after all consumers have migrated). No exclusive locks during the migration window. Application code handles both old and new schema temporarily, which requires coordination between deploy and migration steps.
Use when: multi-service systems, microservices with independent deploy cycles, high-traffic tables that cannot afford a write window
Blue-Green
Fast switchover · Double infrastructure cost
Maintain two identical environments: Blue (live) and Green (new schema). Replicate or stream data from Blue to Green continuously until Green is current, then switch traffic. Rollback is a traffic switch back to Blue, which still holds the old state. Infrastructure cost doubles during the migration window (hours to days). Best combined with expand-contract for the schema changes within each environment.
Use when: major version upgrades, database engine changes, security patches requiring full environment replacement
Shadow Writes
Strong consistency · ~2x disk space
Create a shadow clone of the table with the new schema, synchronise it via CDC (Change Data Capture) or database triggers while the original remains live, backfill historical data, verify lag approaches zero, then perform an atomic table name swap. The old table stays in read-only mode briefly after cutover as a rollback safety net. Stronger consistency guarantees than dual-write but requires approximately 2× the disk space during migration.
Use when: single large tables, column type changes that cannot be done online, replatforming scenarios where the target schema is substantially different
Online DDL
Minimal lock · Limited scope
ALTER TABLE operations that avoid exclusive table locks through concurrent table rebuilds, in-place modification of metadata, or engine-specific online DDL mechanisms. PostgreSQL standard ALTER is millisecond-scale on small tables but acquires exclusive locks on large ones; tools like pgroll and pg_osc wrap the expand-contract pattern to make large-table changes safe. Not all DDL operations support online execution — column type narrowing and constraint additions often still require brief exclusive locks.
Use when: additive changes (new nullable columns, new indexes), small-to-medium tables, or where engine-specific online DDL is confirmed to support the operation type

Expand-Contract — the three phases

Phase 1
Expand
Add new column or table
Keep old structure intact
Deploy new application code
App reads old, writes to both
No exclusive locks · Minutes
Phase 2
Transition
Dual-write to both schemas
Backfill historical data
Validate consistency
Monitor replication lag
Both schemas live · Hours to days
Phase 3
Contract
Switch all reads to new schema
Remove dual-write logic
Drop old column or table
Verify downstream consumers
No exclusive locks · Minutes
A note on event sourcing

A fifth pattern — event sourcing with a schema registry — is gaining relevance specifically for LLM pipelines. Instead of storing current state, event stores record the complete history of business events. Schema evolution becomes additive: new event types are appended without altering historical events. The event store provides the contextual history that LLM agents need for coherent multi-turn reasoning. Anthropic's Model Context Protocol (MCP, November 2024) formalises the interface between LLMs and event sources, making this pattern increasingly viable for AI-driven decision pipelines that require full audit trails. The Living Databases framework (Deshpande, ICDE 2026; arXiv:2605.00676) formalises this concept further, proposing unified computational primitives for schema evolution, versioning, and streaming updates with provenance tracking built in.

Database-specific behaviour guide

The pattern you choose is constrained by the database you are migrating. The gaps between how databases handle schema changes are wider than most guides acknowledge — and the surprises usually appear in production, not in staging. The table below covers the six databases that dominate LLM data pipelines as of 2026.

Database Online DDL safety Zero-downtime pattern Critical gotcha Recommended tool
PostgreSQL Partial pg_repack for large tables (requires ~2× disk); pgroll wraps expand-contract; pg_osc for one-off changes. Standard ALTER TABLE acquires brief exclusive lock even for additive changes. A 100 GB table with 60% bloat shrinks to ~40 GB after pg_repack, but the operation requires approximately 2× target table size free on disk and holds a brief exclusive lock at start and end (Percona, 2025). Flyway + pgroll for CI/CD; Alembic for Python monoliths
ClickHouse High risk EXCHANGE TABLES for atomic name swap; Materialized Views to route INSERTs to new schema in parallel. ALTER TABLE mutations cannot be rolled back. A mutation that fails partway through leaves the table in an inconsistent state. Always test mutations on a non-production replica first (Tinybird, 2026). Converting a MergeTree table to ReplicatedMergeTree requires per-partition attachment rather than a full copy. Atlas (supports ClickHouse); manual migration scripts with EXCHANGE TABLES
DuckDB Limited Standard ALTER TABLE within a single writer process. MVCC allows multiple concurrent reader threads within the same writer process. Single writer, multiple readers only. A second write session blocks or fails — DuckDB locks the database file for writes. This makes it unsuitable for high-concurrency streaming ingestion (DuckDB docs, 2026). Excellent for local development, analytics, and single-process ETL batch jobs. dbt-duckdb for transformation pipelines; SQL migration files for schema changes
Apache Iceberg Full support Native schema evolution: added columns receive new numeric IDs and existing data files are never rewritten. Drop, rename, and reorder columns without touching historical partitions. Partition evolution allows changing the partitioning scheme — old files keep the old layout, new files use the new one, and the query planner handles both transparently. Column IDs are internal — applications must reference columns by name, not position, to avoid breaking after reorder. Column type widening is supported (int → long, float → double); narrowing is not. Built-in schema evolution API; Spark / Flink connectors
Delta Lake Good support mergeSchema: additive-only evolution — new columns from the source DataFrame are automatically added to the target table without requiring manual DDL. overwriteSchema: replaces the entire schema, including column drops and type changes. overwriteSchema is destructive — downstream consumers that expected the old schema will break immediately. Always audit consumers before using it. For large tables, schema changes via mergeSchema are safe; overwriteSchema should be treated as a breaking change (Delta Lake, 2023). dbt + Delta Lake adapter; Databricks Delta Live Tables for streaming
BigQuery Partial Schema changes to existing tables are mostly online. New columns added as NULLABLE or REPEATED are immediately queryable. New columns must be NULLABLE or REPEATED — adding a REQUIRED column to an existing table is not allowed. Modifying schema after recent streaming inserts causes metadata propagation delays (typically minutes) during which query results may reflect an inconsistent schema state (Google Cloud, 2026). BigQuery native schema update API; dbt for transformation layer; Dataform for declarative pipelines

Migration tools: choosing the right fit

The migration pattern determines the approach; the tool determines the operational experience. For teams running heterogeneous stacks — which describes most LLM pipelines with a mix of PostgreSQL for metadata, a vector store for embeddings, and a columnar store for analytics — the tool selection should prioritise database breadth and CI/CD integration over feature depth in any single database.

Tool Best for DB support Rollback Key differentiator
Flyway Microservices, CI/CD automation, Java/Python/Node 50+ databases Automatic per changeset Version-controlled SQL files with minimal configuration; fastest path from zero to migrated in CI pipelines (Flyway v12.3.0, 2026)
Liquibase Database-agnostic strategies, enterprise compliance 50+ databases Built-in rollback to timestamp Supports SQL, XML, YAML, JSON changeset formats; v5.0 introduces cleaner community/commercial separation with the Liquibase Package Manager (LPM); Liquibase Secure adds AI-assisted change governance — flagging, auditing, and tracing AI-generated schema modifications (Liquibase, 2025)
Alembic Python ecosystems, SQLAlchemy-based stacks PostgreSQL, MySQL, SQLite via SQLAlchemy Manual downgrade scripts Migration logic written in Python — allows programmatic generation based on ORM model diff; best choice for Python monoliths where migrations need to interact with application code
dbt Analytics, data transformation, feature engineering Snowflake, BigQuery, Redshift, DuckDB, Postgres Limited (seed + snapshot) Data lineage, testing, documentation built-in; the right layer for managing LLM feature engineering and output transformation pipelines, not raw DDL migrations
Atlas Schema-as-Code, GitOps, cross-database enforcement PostgreSQL, MySQL, ClickHouse, SQL Server, SQLite, CockroachDB Via declarative migration plans 50+ pre-migration analysers that flag destructive changes before they execute; schema drift detection; ClickHouse support now covers clusters, user-defined functions, table projections, and partitions (Atlas v0.37+, Sep 2025)

Vector database migrations: the special case

Vector stores — whether pgvector in PostgreSQL, Pinecone, Weaviate, or a dedicated engine — have a migration characteristic that distinguishes them from relational databases: you cannot partially migrate a vector index. Similarity search requires that all vectors in an index occupy the same geometric space, produced by the same model at the same version. A mixed index of old and new vectors produces query results that are mathematically undefined — the distance between a new 3,072-dimensional vector and an old 768-dimensional vector is not a meaningful similarity score.

The correct migration sequence has five steps that must run in order. Skipping the validation step is the most common source of post-cutover regressions — similarity thresholds calibrated in the old geometric space do not transfer to the new one.

Step 01
Build shadow index
New index created in parallel. Old index continues serving all queries without interruption.
Step 02
Re-generate corpus
Re-embed every document using the new model. Schedule as a background job on its own timeline — independent of the application deployment.
Step 03
Validate recall@k
Run the new index against a held-out evaluation set. Recalibrate similarity thresholds for the new geometric space before any traffic switches.
Step 04
Atomic cutover
Alias swap or EXCHANGE TABLES equivalent. Traffic switches to the new index in a single atomic operation — no partial state.
Step 05
Rollback window
Retain the old index for a defined period before deletion. Define this window before cutover, not after a problem appears.

Models that implement Matryoshka Representation Learning (MRL) reduce this complexity. MRL models produce embeddings that can be truncated to smaller dimensions without retraining — a 3,072-dimensional embedding can be truncated to 768 dimensions and remain semantically valid. This allows phased dimension migration: serve queries at the old dimension count from truncated new embeddings while the full rebuild completes in the background. Not all embedding models support MRL; verify support before planning a phased approach.

Python — parallel index build during embedding migration
import anthropic
from datetime import datetime

client = anthropic.Anthropic()

def migrate_embedding_store(
    old_index: str,
    new_index: str,
    documents: list[dict],
    new_model: str,
    batch_size: int = 100
) -> dict:
    """
    Build new embedding index in parallel without touching the live index.
    Returns migration stats for validation before cutover.
    """
    stats = {"total": len(documents), "succeeded": 0, "failed": 0}

    for i in range(0, len(documents), batch_size):
        batch = documents[i : i + batch_size]

        # Generate new embeddings via Claude Opus 4.7 classification layer
        # or a dedicated embedding model — keep generation separate from indexing
        for doc in batch:
            try:
                new_vector = generate_embedding(doc["text"], model=new_model)
                write_to_shadow_index(new_index, doc["id"], new_vector, doc["metadata"])
                stats["succeeded"] += 1
            except Exception as e:
                stats["failed"] += 1
                log_migration_error(doc["id"], str(e))

    return stats

def validate_and_cutover(old_index: str, new_index: str, eval_set: list[dict]) -> bool:
    """
    Compare retrieval quality on evaluation set before committing to new index.
    Only cut over if recall@10 degradation is below threshold.
    """
    old_recall = compute_recall_at_k(old_index, eval_set, k=10)
    new_recall = compute_recall_at_k(new_index, eval_set, k=10)

    degradation = (old_recall - new_recall) / old_recall
    if degradation > 0.05:  # reject if recall drops more than 5%
        return False

    atomic_index_swap(old_index, new_index)  # alias swap or EXCHANGE TABLES equivalent
    return True

LLM-assisted migrations: the emerging accelerator

One of the more consequential changes in migration practice since 2024 is the use of LLMs to generate migration code — not just as a productivity tool but as a structured pipeline that can handle large-scale code and schema changes that would otherwise require months of manual engineering.

Airbnb published a detailed account of migrating 3,500 React component test files to a new testing framework using an LLM-driven pipeline (Airbnb Engineering, 2026). The pipeline achieved a 97% automated success rate, converting an estimated 1.5 years of manual engineering work into six weeks of pipeline execution. The architecture was key: each file was processed as a discrete, parallelised unit with configurable retries and expanded context windows for files that failed on first pass. The 3% of files that required manual intervention were flagged automatically.

97%
Automated success rate
Airbnb: 3,500 React test files — 1.5 years of work completed in 6 weeks (Airbnb Engineering, 2026)
74.45%
Code changes by LLM
Google: 39 migration projects over 12 months spanning SQL, API, and library migrations (arXiv:2504.09691)
50%
Time reduction
Developer-reported savings across Google's migration programme (arXiv:2504.09691)

A study of large-scale code migrations at Google across 39 distinct migration projects over 12 months found that LLMs generated 74.45% of code changes and 69.46% of edits, with developers reporting a 50% reduction in total time spent (arXiv:2504.09691). The projects spanned SQL migrations, API migrations, and library upgrades — including schema-level changes. The same pattern applies to database migration code: generating the Flyway SQL changesets, the Alembic migration scripts, or the Atlas HCL declarations from schema diffs is a task that LLMs handle well, with human review focused on the destructive operations and the edge cases.

Academic work formalises multiple dimensions of this approach. The Horizon system (VLDB 2024) combines traditional database tooling with LLMs to guide schema object translation — including stored procedures and triggers — achieving syntactically complete and functionally equivalent SQL migrations across database dialects. A model-driven framework for cross-paradigm migration (Ortín, Hoyos, and García-Molina, 2026; arXiv:2604.22415) extends this to heterogeneous stores: it uses a unified intermediate representation to handle transformations between relational and NoSQL schemas, directly relevant for LLM pipelines that combine PostgreSQL with document or vector stores. The SLSM approach (arXiv:2404.03929) proposes a lazy schema migration strategy for distributed databases that defers migration work to background processes, reducing the migration window for high-traffic shared-nothing systems.

Seven practical tips for LLM pipeline migrations

01
Treat the vector index as a separate migration artifact
Plan the embedding rebuild on its own timeline, independent of the application deployment. For large corpora, schedule it as a multi-day background process, validate against an eval set before cutover, and keep the old index available for rollback. Never plan a same-day cutover for both the application code and the vector index rebuild.
02
Start with JSONB, extract when it becomes a hot path
For LLM output storage, JSONB gives you the flexibility to absorb schema changes across model providers without DDL. Once a field is queried in more than 10–15% of requests, extract it to a typed column with an index. The transition from JSONB field to typed column is a standard expand-contract: add column, backfill from JSONB, update queries, drop JSONB field.
03
Never modify a ClickHouse table in production without a replica test
ClickHouse mutations — triggered by ALTER TABLE — modify data parts on disk and cannot be rolled back. A mutation that fails partway through leaves the table in an inconsistent state that requires manual repair. Always run the same mutation on a non-production replica first and confirm it completes without error before applying to production. Use EXCHANGE TABLES for the final cutover, not ALTER TABLE RENAME.
04
Store prompts as immutable versioned records from day one
Retrofitting prompt versioning into a system that stores prompts as mutable strings is painful. Start with a prompt_versions table: id, template_hash, created_at, variables_schema, output_schema, status (staging / prod / deprecated), performance_notes. Link every LLM inference log to a prompt_version_id. This is the prerequisite for meaningful regression testing when the next model is released.
05
Use Atlas for ClickHouse and cross-database enforcement
Most migration tools do not support ClickHouse. Atlas (v0.37+, Sep 2025) does — including cluster-aware ClickHouse changes — and its pre-migration analyser suite flags destructive operations before they execute. For teams running PostgreSQL and ClickHouse in the same pipeline (transactional data in Postgres, analytics in ClickHouse), Atlas provides a unified schema-as-code layer with consistent rollback semantics across both.
06
Design classification schemas for extension, not enumeration
Enum columns lock you into a fixed label set. When a new classification category is added — which happens regularly in any LLM-powered monitoring system — an enum column requires a DDL change on potentially very large tables. Use a classifications junction table or a JSONB array of {label, score, model_version} objects. New labels are rows in the junction table, not schema changes. Backfilling existing records with a programmatic classifier avoids the cold-start problem for new labels.
07
Run migration-generated code through LLM review before execution
When using LLMs to generate migration scripts (Flyway changesets, Alembic scripts, Atlas HCL), treat the generated code as a first draft, not a final artifact. Run it through a second LLM review pass — Claude Opus 4.7 handles this well — with a prompt that explicitly asks it to identify irreversible operations, flag missing rollback steps, and check for data-loss scenarios. The combination of LLM generation and LLM review catches a different class of errors than human review alone.

Choosing the right pattern for your pipeline

Decision framework
What schema surface are you migrating?
Vector store
Full rebuild protocol
Parallel shadow index → re-generate corpus → validate recall@k → atomic alias swap → retain old index for rollback window. Plan the rebuild on its own timeline, independent of the application deployment.
Lakehouse (Iceberg / Delta)
Native schema evolution
Use the built-in API. Iceberg assigns new column IDs without rewriting data files. Delta mergeSchema handles additive changes safely. No external tooling needed for standard evolution.
Relational DB
Engine-specific — see below
Behaviour varies significantly. Never apply the same strategy to PostgreSQL and ClickHouse without engine-specific validation. Check the database guide section above before committing to a pattern.
Relational DB: which engine?
ClickHouse
EXCHANGE TABLES for cutover
Mutations cannot be rolled back. Always run on a replica first. Never use ALTER TABLE for production critical changes.
PostgreSQL — high traffic
Expand-Contract + pgroll
Raw ALTER TABLE acquires exclusive locks on large tables. Wrap with pgroll or pg_osc to keep the table online throughout the migration window.
PostgreSQL — small table
Online DDL (additive only)
New nullable columns and new indexes are millisecond-scale. Test timing on a staging replica before applying to production regardless of table size estimate.
BigQuery / DuckDB
Engine constraint first
BigQuery: new columns must be NULLABLE or REPEATED. DuckDB: single writer lock — no concurrent write sessions regardless of migration pattern chosen.

The broader principle is that schema migration in LLM pipelines is more complex than in traditional CRUD applications not because the databases are fundamentally different, but because LLM systems add three additional schema surfaces — vectors, prompt templates, and classification taxonomies — each with its own migration semantics that standard database tooling does not cover. The teams that handle this well treat each surface as a first-class engineering concern with its own migration plan, rollback procedure, and validation criteria.

References
  1. Airbnb Engineering. (2026). Accelerating large-scale test migration with LLMs. Airbnb Engineering Blog. medium.com/airbnb-engineering
  2. Migrating Code At Scale With LLMs At Google. (2025). arXiv:2504.09691
  3. Emani et al. (2024). Horizon: Robust Checks for SQL Migration Using LLMs. VLDB Vol. 18. vldb.org
  4. SLSM: An Efficient Strategy for Lazy Schema Migration on Shared-Nothing Databases. (2024). arXiv:2404.03929
  5. Ortín, M.J., Hoyos, J.R., and García-Molina, J. (2026). A Model-Driven Approach to Database Migration with a Unified Data Model. arXiv:2604.22415
  6. Deshpande, A. (2026). Living Databases: A Unified Model for Continuous Schema Evolution, Versioning, and Transformations. Proceedings of ICDE 2026. arXiv:2605.00676
  7. Automatic Labelling with Open-source LLMs using Dynamic Label Schema Integration. (2025). arXiv:2501.12332
  8. Apache Software Foundation. (2026). Apache Iceberg — Evolution. Official documentation. iceberg.apache.org
  9. Delta Lake Project. (2023). Delta Lake Schema Evolution. Official blog. delta.io
  10. DuckDB Foundation. (2026). Concurrency — DuckDB. Official documentation. duckdb.org
  11. Google Cloud. (2026). Modifying table schemas. BigQuery documentation. cloud.google.com/bigquery
  12. Ariga. (2024). Strategies for Reliable Schema Migrations. Atlas blog. atlasgo.io
M
Michele Mader
Technical Leader · AI Systems & Data Engineering

I lead technical direction on AI-driven data products for enterprise clients — defining architecture, making stack decisions, and owning delivery from roadmap to production.

Connect on LinkedIn