Jaco van der Laan

🧩 Evolving Metadata-Driven Data Models — From DDL Generation to Automated Schema Migration

09/11/2025  ·  Data Engineering  ·  Model Versioning  ·  SQL Code Generation

metadata migration sql
‹ ›

How metadata-as-code principles extend beyond model generation to manage safe, automated, and traceable schema evolution in production


🧩 Evolving Metadata-Driven Data Models — From DDL Generation to Automated Schema Migration

How metadata-as-code principles extend beyond model generation to manage safe, automated, and traceable schema evolution in production


💡 Introduction — Beyond CREATE TABLE

In my previous article, we explored how conceptual and logical metadata can automatically generate physical data models — turning business meaning into structure and SQL.

After publication, Kristian Poulsen asked a question that perfectly captures the next step in this journey:

“If the end goal is a set of CREATE TABLE statements, how do you manage changes to existing tables in production?”

It’s an excellent question — because in practice, the end goal isn’t a single DDL file. It’s a continuous process of schema evolution , safely moving from one model version to the next.

In metadata-driven environments, model generation and model evolution are two sides of the same coin.

1️⃣ The Real Goal: Continuous Schema Evolution

In modern data platforms, your schema changes as frequently as your code. Business definitions evolve, new data arrives, and pipelines must adapt.

So the objective isn’t to generate one perfect schema. It’s to continuously generate migration scripts that evolve your database in sync with your metadata.

Think of it like DevOps for your data model:


2️⃣ From Model Changes to Migration Scripts

In a metadata-as-code setup, every change to a model triggers a controlled workflow.

Here’s what happens when you modify your YAML:

  1. Parse both versions of the metadata (before and after commit).
  2. Compute the diff between logical and physical layers.
  3. Generate migration DDL (ALTER TABLE, CREATE TABLE, DROP COLUMN, etc.).
  4. Validate integrity — naming, keys, relationships, lineage.
  5. Create a pull request with both the YAML and generated SQL.

Example metadata change:

# logical/customer.yaml  
- attributes:  
-   - name: email_address  
+   - name: email  
+     derived_from: contact_point.email

Automatically generates:

ALTER TABLE customer ADD COLUMN email STRING;

This process ensures your schema, lineage, and documentation all evolve together — versioned, reviewable, and reversible.


3️⃣ Handling Breaking vs. Non-Breaking Changes

Schema changes vary in impact. Some are safe and incremental, others require multiple steps to avoid breaking downstream systems.

These strategies can even be encoded in YAML metadata:

migration_strategy:  
  email_address:  
    action: rename  
    new_name: email  
    phase: 2-step

The model itself defines how evolution should occur — metadata driving not just structure, but change management.


4️⃣ Versioned Models as Contracts

Not every schema change should break your consumers. To achieve long-term stability, we separate internal evolution from external contracts.

Stable views or dbt models act as the published interface, while underlying physical tables evolve freely.

exposure:  
  name: customer_view  
  source: customer  
  fields:  
    - name: id  
    - name: name  
    - name: email

Downstream users query customer_view, not customer_table. This creates semantic stability — the business logic remains consistent even as physical storage adapts underneath.


5️⃣ Continuous Metadata Integration (CMI)

The same DevOps mindset applies to metadata itself — a discipline I call Continuous Metadata Integration (CMI).

In CMI, every modeling change is treated as code:

  • Pre-commit hooks validate structure, lineage, and naming.
  • CI pipelines generate ERDs, documentation, and migration DDL automatically.
  • Pull requests serve as peer reviews for metadata changes.
  • Deployment pipelines apply generated migrations through tools like Flyway, Liquibase, dbt, or custom orchestrators.

This process replaces the “big-bang model release” with small, verifiable increments. Your models evolve continuously, just like application code — but with complete semantic traceability.


6️⃣ From YAML to Production — The Lifecycle

Let’s summarize the flow:

YAML → Git Commit → CI Validation → Metadata Diff  
→ DDL Migration → Review & Approval → Deploy → Sync Metadata State

Each change is fully auditable:

  • ✅ Who made it
  • ✅ What changed (conceptual, logical, physical)
  • ✅ Which SQL it generated
  • ✅ When it was deployed
  • ✅ Where it impacts downstream models

That’s not just lineage — that’s governed evolution.


7️⃣ Why This Matters

Traditional tools focus on design time. Modern data teams operate in runtime — constantly adapting to new requirements.

By integrating conceptual, logical, and physical metadata into one version-controlled flow, we:

  • Eliminate manual schema drift
  • Enable safe collaboration at scale
  • Preserve business meaning through every technical change
  • Bring traceability , automation , and agility to the heart of data modeling

This is the bridge between data modeling and DevOps — a living, executable architecture.


🧭 In Summary

Metadata-driven modeling isn’t just about generating DDLs. It’s about managing evolution — continuously, safely, and collaboratively.

When every schema change flows from metadata to migration to deployment, you move from static documentation to a self-adapting system — where models, databases, and business meaning stay permanently aligned.


🔜 Coming Next

In the next article, we’ll make this tangible with a Python implementation :
how to detect metadata diffs, generate SQL migrations automatically, and integrate the whole flow into Git and CI/CD.

🧠 Coming soon: 👉 Automating Schema Migrations from Metadata — Diffing, DDL, and DevOps in Action.